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 "xfa/src/foxitlib.h"
8 #include "xfa/src/fwl/src/core/include/fwl_threadimp.h"
9 #include "xfa/src/fwl/src/core/include/fwl_appimp.h"
10 #include "xfa/src/fwl/src/core/include/fwl_targetimp.h"
11 #include "xfa/src/fwl/src/core/include/fwl_noteimp.h"
12 #include "xfa/src/fwl/src/core/include/fwl_widgetimp.h"
13 #include "xfa/src/fwl/src/core/include/fwl_panelimp.h"
14 #include "xfa/src/fwl/src/core/include/fwl_formimp.h"
15 #include "xfa/src/fwl/src/core/include/fwl_widgetmgrimp.h"
16 #include "xfa/src/fwl/src/basewidget/include/fwl_scrollbarimp.h"
17 #include "xfa/src/fwl/src/basewidget/include/fwl_editimp.h"
18 #include "xfa/src/fwl/src/basewidget/include/fwl_listboximp.h"
19 #include "xfa/src/fwl/src/basewidget/include/fwl_formproxyimp.h"
20 #include "xfa/src/fwl/src/basewidget/include/fwl_comboboximp.h"
21 
22 // static
Create(const CFWL_WidgetImpProperties & properties)23 IFWL_ComboBox* IFWL_ComboBox::Create(
24     const CFWL_WidgetImpProperties& properties) {
25   IFWL_ComboBox* pComboBox = new IFWL_ComboBox;
26   CFWL_ComboBoxImp* pComboBoxImpl = new CFWL_ComboBoxImp(properties, nullptr);
27   pComboBox->SetImpl(pComboBoxImpl);
28   pComboBoxImpl->SetInterface(pComboBox);
29   return pComboBox;
30 }
IFWL_ComboBox()31 IFWL_ComboBox::IFWL_ComboBox() {}
GetCurSel()32 int32_t IFWL_ComboBox::GetCurSel() {
33   return static_cast<CFWL_ComboBoxImp*>(GetImpl())->GetCurSel();
34 }
SetCurSel(int32_t iSel)35 FWL_ERR IFWL_ComboBox::SetCurSel(int32_t iSel) {
36   return static_cast<CFWL_ComboBoxImp*>(GetImpl())->SetCurSel(iSel);
37 }
SetEditText(const CFX_WideString & wsText)38 FWL_ERR IFWL_ComboBox::SetEditText(const CFX_WideString& wsText) {
39   return static_cast<CFWL_ComboBoxImp*>(GetImpl())->SetEditText(wsText);
40 }
GetEditTextLength() const41 int32_t IFWL_ComboBox::GetEditTextLength() const {
42   return static_cast<CFWL_ComboBoxImp*>(GetImpl())->GetEditTextLength();
43 }
GetEditText(CFX_WideString & wsText,int32_t nStart,int32_t nCount) const44 FWL_ERR IFWL_ComboBox::GetEditText(CFX_WideString& wsText,
45                                    int32_t nStart,
46                                    int32_t nCount) const {
47   return static_cast<CFWL_ComboBoxImp*>(GetImpl())
48       ->GetEditText(wsText, nStart, nCount);
49 }
SetEditSelRange(int32_t nStart,int32_t nCount)50 FWL_ERR IFWL_ComboBox::SetEditSelRange(int32_t nStart, int32_t nCount) {
51   return static_cast<CFWL_ComboBoxImp*>(GetImpl())
52       ->SetEditSelRange(nStart, nCount);
53 }
GetEditSelRange(int32_t nIndex,int32_t & nStart)54 int32_t IFWL_ComboBox::GetEditSelRange(int32_t nIndex, int32_t& nStart) {
55   return static_cast<CFWL_ComboBoxImp*>(GetImpl())
56       ->GetEditSelRange(nIndex, nStart);
57 }
GetEditLimit()58 int32_t IFWL_ComboBox::GetEditLimit() {
59   return static_cast<CFWL_ComboBoxImp*>(GetImpl())->GetEditLimit();
60 }
SetEditLimit(int32_t nLimit)61 FWL_ERR IFWL_ComboBox::SetEditLimit(int32_t nLimit) {
62   return static_cast<CFWL_ComboBoxImp*>(GetImpl())->SetEditLimit(nLimit);
63 }
EditDoClipboard(int32_t iCmd)64 FWL_ERR IFWL_ComboBox::EditDoClipboard(int32_t iCmd) {
65   return static_cast<CFWL_ComboBoxImp*>(GetImpl())->EditDoClipboard(iCmd);
66 }
EditRedo(const CFX_ByteStringC & bsRecord)67 FX_BOOL IFWL_ComboBox::EditRedo(const CFX_ByteStringC& bsRecord) {
68   return static_cast<CFWL_ComboBoxImp*>(GetImpl())->EditRedo(bsRecord);
69 }
EditUndo(const CFX_ByteStringC & bsRecord)70 FX_BOOL IFWL_ComboBox::EditUndo(const CFX_ByteStringC& bsRecord) {
71   return static_cast<CFWL_ComboBoxImp*>(GetImpl())->EditUndo(bsRecord);
72 }
GetListBoxt()73 IFWL_ListBox* IFWL_ComboBox::GetListBoxt() {
74   return static_cast<CFWL_ComboBoxImp*>(GetImpl())->GetListBoxt();
75 }
AfterFocusShowDropList()76 FX_BOOL IFWL_ComboBox::AfterFocusShowDropList() {
77   return static_cast<CFWL_ComboBoxImp*>(GetImpl())->AfterFocusShowDropList();
78 }
OpenDropDownList(FX_BOOL bActivate)79 FX_ERR IFWL_ComboBox::OpenDropDownList(FX_BOOL bActivate) {
80   return static_cast<CFWL_ComboBoxImp*>(GetImpl())->OpenDropDownList(bActivate);
81 }
EditCanUndo()82 FX_BOOL IFWL_ComboBox::EditCanUndo() {
83   return static_cast<CFWL_ComboBoxImp*>(GetImpl())->EditCanUndo();
84 }
EditCanRedo()85 FX_BOOL IFWL_ComboBox::EditCanRedo() {
86   return static_cast<CFWL_ComboBoxImp*>(GetImpl())->EditCanRedo();
87 }
EditUndo()88 FX_BOOL IFWL_ComboBox::EditUndo() {
89   return static_cast<CFWL_ComboBoxImp*>(GetImpl())->EditUndo();
90 }
EditRedo()91 FX_BOOL IFWL_ComboBox::EditRedo() {
92   return static_cast<CFWL_ComboBoxImp*>(GetImpl())->EditRedo();
93 }
EditCanCopy()94 FX_BOOL IFWL_ComboBox::EditCanCopy() {
95   return static_cast<CFWL_ComboBoxImp*>(GetImpl())->EditCanCopy();
96 }
EditCanCut()97 FX_BOOL IFWL_ComboBox::EditCanCut() {
98   return static_cast<CFWL_ComboBoxImp*>(GetImpl())->EditCanCut();
99 }
EditCanSelectAll()100 FX_BOOL IFWL_ComboBox::EditCanSelectAll() {
101   return static_cast<CFWL_ComboBoxImp*>(GetImpl())->EditCanSelectAll();
102 }
EditCopy(CFX_WideString & wsCopy)103 FX_BOOL IFWL_ComboBox::EditCopy(CFX_WideString& wsCopy) {
104   return static_cast<CFWL_ComboBoxImp*>(GetImpl())->EditCopy(wsCopy);
105 }
EditCut(CFX_WideString & wsCut)106 FX_BOOL IFWL_ComboBox::EditCut(CFX_WideString& wsCut) {
107   return static_cast<CFWL_ComboBoxImp*>(GetImpl())->EditCut(wsCut);
108 }
EditPaste(const CFX_WideString & wsPaste)109 FX_BOOL IFWL_ComboBox::EditPaste(const CFX_WideString& wsPaste) {
110   return static_cast<CFWL_ComboBoxImp*>(GetImpl())->EditPaste(wsPaste);
111 }
EditSelectAll()112 FX_BOOL IFWL_ComboBox::EditSelectAll() {
113   return static_cast<CFWL_ComboBoxImp*>(GetImpl())->EditSelectAll();
114 }
EditDelete()115 FX_BOOL IFWL_ComboBox::EditDelete() {
116   return static_cast<CFWL_ComboBoxImp*>(GetImpl())->EditDelete();
117 }
EditDeSelect()118 FX_BOOL IFWL_ComboBox::EditDeSelect() {
119   return static_cast<CFWL_ComboBoxImp*>(GetImpl())->EditDeSelect();
120 }
GetBBox(CFX_RectF & rect)121 FWL_ERR IFWL_ComboBox::GetBBox(CFX_RectF& rect) {
122   return static_cast<CFWL_ComboBoxImp*>(GetImpl())->GetBBox(rect);
123 }
EditModifyStylesEx(FX_DWORD dwStylesExAdded,FX_DWORD dwStylesExRemoved)124 FWL_ERR IFWL_ComboBox::EditModifyStylesEx(FX_DWORD dwStylesExAdded,
125                                           FX_DWORD dwStylesExRemoved) {
126   return static_cast<CFWL_ComboBoxImp*>(GetImpl())
127       ->EditModifyStylesEx(dwStylesExAdded, dwStylesExRemoved);
128 }
129 
CFWL_ComboEditImp(const CFWL_WidgetImpProperties & properties,IFWL_Widget * pOuter)130 CFWL_ComboEditImp::CFWL_ComboEditImp(const CFWL_WidgetImpProperties& properties,
131                                      IFWL_Widget* pOuter)
132     : CFWL_EditImp(properties, pOuter) {
133   m_pOuter = static_cast<CFWL_ComboBoxImp*>(pOuter->GetImpl());
134 }
135 
CFWL_ComboEditImpDelegate(CFWL_ComboEditImp * pOwner)136 CFWL_ComboEditImpDelegate::CFWL_ComboEditImpDelegate(CFWL_ComboEditImp* pOwner)
137     : CFWL_EditImpDelegate(pOwner), m_pOwner(pOwner) {
138 }
OnProcessMessage(CFWL_Message * pMessage)139 int32_t CFWL_ComboEditImpDelegate::OnProcessMessage(CFWL_Message* pMessage) {
140   if (!pMessage)
141     return 0;
142   FX_DWORD dwMsgCode = pMessage->GetClassID();
143   FX_BOOL backDefault = TRUE;
144   switch (dwMsgCode) {
145     case FWL_MSGHASH_SetFocus:
146     case FWL_MSGHASH_KillFocus: {
147       if (dwMsgCode == FWL_MSGHASH_SetFocus) {
148         m_pOwner->m_pProperties->m_dwStates |= FWL_WGTSTATE_Focused;
149       } else {
150         m_pOwner->m_pProperties->m_dwStates &= ~FWL_WGTSTATE_Focused;
151       }
152       backDefault = FALSE;
153       break;
154     }
155     case FWL_MSGHASH_Mouse: {
156       CFWL_MsgMouse* pMsg = static_cast<CFWL_MsgMouse*>(pMessage);
157       if ((pMsg->m_dwCmd == FWL_MSGMOUSECMD_LButtonDown) &&
158           ((m_pOwner->m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) == 0)) {
159         m_pOwner->SetSelected();
160         m_pOwner->SetComboBoxFocus(TRUE);
161       }
162       break;
163     }
164     default: {}
165   }
166   if (!backDefault) {
167     return 1;
168   }
169   return CFWL_EditImpDelegate::OnProcessMessage(pMessage);
170 }
ClearSelected()171 void CFWL_ComboEditImp::ClearSelected() {
172   ClearSelections();
173   Repaint(&m_rtClient);
174 }
SetSelected()175 void CFWL_ComboEditImp::SetSelected() {
176   FlagFocus(TRUE);
177   EndCaret();
178   AddSelRange(0);
179 }
EndCaret()180 void CFWL_ComboEditImp::EndCaret() {
181   m_pEdtEngine->MoveCaretPos(MC_End);
182 }
FlagFocus(FX_BOOL bSet)183 void CFWL_ComboEditImp::FlagFocus(FX_BOOL bSet) {
184   if (bSet) {
185     m_pProperties->m_dwStates |= FWL_WGTSTATE_Focused;
186   } else {
187     m_pProperties->m_dwStates &= ~FWL_WGTSTATE_Focused;
188     ShowCaret(FALSE);
189   }
190 };
SetComboBoxFocus(FX_BOOL bSet)191 void CFWL_ComboEditImp::SetComboBoxFocus(FX_BOOL bSet) {
192   m_pOuter->SetFocus(bSet);
193 }
CFWL_ComboListImp(const CFWL_WidgetImpProperties & properties,IFWL_Widget * pOuter)194 CFWL_ComboListImp::CFWL_ComboListImp(const CFWL_WidgetImpProperties& properties,
195                                      IFWL_Widget* pOuter)
196     : CFWL_ListBoxImp(properties, pOuter), m_bNotifyOwner(TRUE) {
197   FXSYS_assert(pOuter != NULL);
198 }
Initialize()199 FWL_ERR CFWL_ComboListImp::Initialize() {
200   if (CFWL_ListBoxImp::Initialize() != FWL_ERR_Succeeded)
201     return FWL_ERR_Indefinite;
202   delete m_pDelegate;
203   m_pDelegate = new CFWL_ComboListImpDelegate(this);
204   return FWL_ERR_Succeeded;
205 }
Finalize()206 FWL_ERR CFWL_ComboListImp::Finalize() {
207   delete m_pDelegate;
208   m_pDelegate = nullptr;
209   return CFWL_ListBoxImp::Finalize();
210 }
MatchItem(const CFX_WideString & wsMatch)211 int32_t CFWL_ComboListImp::MatchItem(const CFX_WideString& wsMatch) {
212   if (wsMatch.IsEmpty()) {
213     return -1;
214   }
215   if (!m_pProperties->m_pDataProvider)
216     return -1;
217   IFWL_ListBoxDP* pData =
218       static_cast<IFWL_ListBoxDP*>(m_pProperties->m_pDataProvider);
219   int32_t iCount = pData->CountItems(m_pInterface);
220   for (int32_t i = 0; i < iCount; i++) {
221     FWL_HLISTITEM hItem = pData->GetItem(m_pInterface, i);
222     CFX_WideString wsText;
223     pData->GetItemText(m_pInterface, hItem, wsText);
224     FX_STRSIZE pos = wsText.Find(wsMatch.c_str());
225     if (!pos) {
226       return i;
227     }
228   }
229   return -1;
230 }
ChangeSelected(int32_t iSel)231 void CFWL_ComboListImp::ChangeSelected(int32_t iSel) {
232   if (!m_pProperties->m_pDataProvider)
233     return;
234   IFWL_ListBoxDP* pData =
235       static_cast<IFWL_ListBoxDP*>(m_pProperties->m_pDataProvider);
236   FWL_HLISTITEM hItem = pData->GetItem(m_pInterface, iSel);
237   CFX_RectF rtInvalidate;
238   rtInvalidate.Reset();
239   FWL_HLISTITEM hOld = GetSelItem(0);
240   int32_t iOld = pData->GetItemIndex(m_pInterface, hOld);
241   if (iOld == iSel) {
242     return;
243   } else if (iOld > -1) {
244     GetItemRect(iOld, rtInvalidate);
245     SetSelItem(hOld, FALSE);
246   }
247   if (hItem) {
248     CFX_RectF rect;
249     GetItemRect(iSel, rect);
250     rtInvalidate.Union(rect);
251     FWL_HLISTITEM hSel = pData->GetItem(m_pInterface, iSel);
252     SetSelItem(hSel, TRUE);
253   }
254   if (!rtInvalidate.IsEmpty()) {
255     Repaint(&rtInvalidate);
256   }
257 }
CountItems()258 int32_t CFWL_ComboListImp::CountItems() {
259   IFWL_ListBoxDP* pData =
260       static_cast<IFWL_ListBoxDP*>(m_pProperties->m_pDataProvider);
261   return pData ? pData->CountItems(m_pInterface) : 0;
262 }
GetItemRect(int32_t nIndex,CFX_RectF & rtItem)263 void CFWL_ComboListImp::GetItemRect(int32_t nIndex, CFX_RectF& rtItem) {
264   IFWL_ListBoxDP* pData =
265       static_cast<IFWL_ListBoxDP*>(m_pProperties->m_pDataProvider);
266   FWL_HLISTITEM hItem = pData->GetItem(m_pInterface, nIndex);
267   pData->GetItemRect(m_pInterface, hItem, rtItem);
268 }
ClientToOuter(FX_FLOAT & fx,FX_FLOAT & fy)269 void CFWL_ComboListImp::ClientToOuter(FX_FLOAT& fx, FX_FLOAT& fy) {
270   fx += m_pProperties->m_rtWidget.left, fy += m_pProperties->m_rtWidget.top;
271   IFWL_Widget* pOwner = GetOwner();
272   if (!pOwner)
273     return;
274   pOwner->TransformTo(m_pOuter, fx, fy);
275 }
SetFocus(FX_BOOL bSet)276 void CFWL_ComboListImp::SetFocus(FX_BOOL bSet) {
277   CFWL_WidgetImp::SetFocus(bSet);
278 }
CFWL_ComboListImpDelegate(CFWL_ComboListImp * pOwner)279 CFWL_ComboListImpDelegate::CFWL_ComboListImpDelegate(CFWL_ComboListImp* pOwner)
280     : CFWL_ListBoxImpDelegate(pOwner), m_pOwner(pOwner) {
281 }
OnProcessMessage(CFWL_Message * pMessage)282 int32_t CFWL_ComboListImpDelegate::OnProcessMessage(CFWL_Message* pMessage) {
283   if (!pMessage)
284     return 0;
285   FX_DWORD dwHashCode = pMessage->GetClassID();
286   FX_BOOL backDefault = TRUE;
287   if (dwHashCode == FWL_MSGHASH_SetFocus ||
288       dwHashCode == FWL_MSGHASH_KillFocus) {
289     OnDropListFocusChanged(pMessage, dwHashCode == FWL_MSGHASH_SetFocus);
290   } else if (dwHashCode == FWL_MSGHASH_Mouse) {
291     CFWL_MsgMouse* pMsg = static_cast<CFWL_MsgMouse*>(pMessage);
292     if (m_pOwner->IsShowScrollBar(TRUE) && m_pOwner->m_pVertScrollBar) {
293       CFX_RectF rect;
294       m_pOwner->m_pVertScrollBar->GetWidgetRect(rect);
295       if (rect.Contains(pMsg->m_fx, pMsg->m_fy)) {
296         pMsg->m_fx -= rect.left;
297         pMsg->m_fy -= rect.top;
298         IFWL_WidgetDelegate* pDelegate =
299             m_pOwner->m_pVertScrollBar->SetDelegate(NULL);
300         return pDelegate->OnProcessMessage(pMsg);
301       }
302     }
303     FX_DWORD dwCmd = pMsg->m_dwCmd;
304     switch (dwCmd) {
305       case FWL_MSGMOUSECMD_MouseMove: {
306         backDefault = FALSE;
307         OnDropListMouseMove(pMsg);
308         break;
309       }
310       case FWL_MSGMOUSECMD_LButtonDown: {
311         backDefault = FALSE;
312         OnDropListLButtonDown(pMsg);
313         break;
314       }
315       case FWL_MSGMOUSECMD_LButtonUp: {
316         backDefault = FALSE;
317         OnDropListLButtonUp(pMsg);
318         break;
319       }
320       default: {}
321     }
322   } else if (dwHashCode == FWL_MSGHASH_Key) {
323     backDefault = !OnDropListKey(static_cast<CFWL_MsgKey*>(pMessage));
324   }
325   if (!backDefault) {
326     return 1;
327   }
328   return CFWL_ListBoxImpDelegate::OnProcessMessage(pMessage);
329 }
OnDropListFocusChanged(CFWL_Message * pMsg,FX_BOOL bSet)330 void CFWL_ComboListImpDelegate::OnDropListFocusChanged(CFWL_Message* pMsg,
331                                                        FX_BOOL bSet) {
332   if (!bSet) {
333     CFWL_MsgKillFocus* pKill = static_cast<CFWL_MsgKillFocus*>(pMsg);
334     CFWL_ComboBoxImp* pOuter =
335         static_cast<CFWL_ComboBoxImp*>(m_pOwner->m_pOuter->GetImpl());
336     if (pKill->m_pSetFocus == m_pOwner->m_pOuter ||
337         pKill->m_pSetFocus == pOuter->m_pEdit.get()) {
338       pOuter->ShowDropList(FALSE);
339     }
340   }
341 }
OnDropListMouseMove(CFWL_MsgMouse * pMsg)342 int32_t CFWL_ComboListImpDelegate::OnDropListMouseMove(CFWL_MsgMouse* pMsg) {
343   if (m_pOwner->m_rtClient.Contains(pMsg->m_fx, pMsg->m_fy)) {
344     if (m_pOwner->m_bNotifyOwner) {
345       m_pOwner->m_bNotifyOwner = FALSE;
346     }
347     if (m_pOwner->IsShowScrollBar(TRUE) && m_pOwner->m_pVertScrollBar) {
348       CFX_RectF rect;
349       m_pOwner->m_pVertScrollBar->GetWidgetRect(rect);
350       if (rect.Contains(pMsg->m_fx, pMsg->m_fy)) {
351         return 1;
352       }
353     }
354     FWL_HLISTITEM hItem = m_pOwner->GetItemAtPoint(pMsg->m_fx, pMsg->m_fy);
355     if (hItem) {
356       if (!m_pOwner->m_pProperties->m_pDataProvider)
357         return 0;
358       IFWL_ListBoxDP* pData = static_cast<IFWL_ListBoxDP*>(
359           m_pOwner->m_pProperties->m_pDataProvider);
360       int32_t iSel = pData->GetItemIndex(m_pOwner->m_pInterface, hItem);
361       CFWL_EvtCmbHoverChanged event;
362       event.m_pSrcTarget = m_pOwner->m_pOuter;
363       event.m_iCurHover = iSel;
364       m_pOwner->DispatchEvent(&event);
365       m_pOwner->ChangeSelected(iSel);
366     }
367   } else if (m_pOwner->m_bNotifyOwner) {
368     m_pOwner->ClientToOuter(pMsg->m_fx, pMsg->m_fy);
369     CFWL_ComboBoxImp* pOuter =
370         static_cast<CFWL_ComboBoxImp*>(m_pOwner->m_pOuter->GetImpl());
371     pOuter->m_pDelegate->OnProcessMessage(pMsg);
372   }
373   return 1;
374 }
OnDropListLButtonDown(CFWL_MsgMouse * pMsg)375 int32_t CFWL_ComboListImpDelegate::OnDropListLButtonDown(CFWL_MsgMouse* pMsg) {
376   if (m_pOwner->m_rtClient.Contains(pMsg->m_fx, pMsg->m_fy)) {
377     return 0;
378   }
379   CFWL_ComboBoxImp* pOuter =
380       static_cast<CFWL_ComboBoxImp*>(m_pOwner->m_pOuter->GetImpl());
381   pOuter->ShowDropList(FALSE);
382   return 1;
383 }
OnDropListLButtonUp(CFWL_MsgMouse * pMsg)384 int32_t CFWL_ComboListImpDelegate::OnDropListLButtonUp(CFWL_MsgMouse* pMsg) {
385   CFWL_ComboBoxImp* pOuter =
386       static_cast<CFWL_ComboBoxImp*>(m_pOwner->m_pOuter->GetImpl());
387   if (m_pOwner->m_bNotifyOwner) {
388     m_pOwner->ClientToOuter(pMsg->m_fx, pMsg->m_fy);
389     pOuter->m_pDelegate->OnProcessMessage(pMsg);
390   } else {
391     if (m_pOwner->IsShowScrollBar(TRUE) && m_pOwner->m_pVertScrollBar) {
392       CFX_RectF rect;
393       m_pOwner->m_pVertScrollBar->GetWidgetRect(rect);
394       if (rect.Contains(pMsg->m_fx, pMsg->m_fy)) {
395         return 1;
396       }
397     }
398     pOuter->ShowDropList(FALSE);
399     FWL_HLISTITEM hItem = m_pOwner->GetItemAtPoint(pMsg->m_fx, pMsg->m_fy);
400     if (hItem) {
401       pOuter->ProcessSelChanged(TRUE);
402     }
403   }
404   return 1;
405 }
OnDropListKey(CFWL_MsgKey * pKey)406 int32_t CFWL_ComboListImpDelegate::OnDropListKey(CFWL_MsgKey* pKey) {
407   CFWL_ComboBoxImp* pOuter =
408       static_cast<CFWL_ComboBoxImp*>(m_pOwner->m_pOuter->GetImpl());
409   FX_BOOL bPropagate = FALSE;
410   if (pKey->m_dwCmd == FWL_MSGKEYCMD_KeyDown) {
411     FX_DWORD dwKeyCode = pKey->m_dwKeyCode;
412     switch (dwKeyCode) {
413       case FWL_VKEY_Return:
414       case FWL_VKEY_Escape: {
415         pOuter->ShowDropList(FALSE);
416         return 1;
417       }
418       case FWL_VKEY_Up:
419       case FWL_VKEY_Down: {
420         OnDropListKeyDown(pKey);
421         pOuter->SetDelegate(nullptr);
422         pOuter->ProcessSelChanged(FALSE);
423         return 1;
424       }
425       default: { bPropagate = TRUE; }
426     }
427   } else if (pKey->m_dwCmd == FWL_MSGKEYCMD_Char) {
428     bPropagate = TRUE;
429   }
430   if (bPropagate) {
431     pKey->m_pDstTarget = m_pOwner->m_pOuter;
432     pOuter->m_pDelegate->OnProcessMessage(pKey);
433     return 1;
434   }
435   return 0;
436 }
OnDropListKeyDown(CFWL_MsgKey * pKey)437 void CFWL_ComboListImpDelegate::OnDropListKeyDown(CFWL_MsgKey* pKey) {
438   FX_DWORD dwKeyCode = pKey->m_dwKeyCode;
439   switch (dwKeyCode) {
440     case FWL_VKEY_Up:
441     case FWL_VKEY_Down:
442     case FWL_VKEY_Home:
443     case FWL_VKEY_End: {
444       CFWL_ComboBoxImp* pOuter =
445           static_cast<CFWL_ComboBoxImp*>(m_pOwner->m_pOuter->GetImpl());
446       IFWL_ListBoxDP* pData = static_cast<IFWL_ListBoxDP*>(
447           m_pOwner->m_pProperties->m_pDataProvider);
448       FWL_HLISTITEM hItem =
449           pData->GetItem(m_pOwner->m_pInterface, pOuter->m_iCurSel);
450       hItem = m_pOwner->GetItem(hItem, dwKeyCode);
451       if (!hItem) {
452         break;
453       }
454       m_pOwner->SetSelection(hItem, hItem, TRUE);
455       m_pOwner->ScrollToVisible(hItem);
456       CFX_RectF rtInvalidate;
457       rtInvalidate.Set(0, 0, m_pOwner->m_pProperties->m_rtWidget.width,
458                        m_pOwner->m_pProperties->m_rtWidget.height);
459       m_pOwner->Repaint(&rtInvalidate);
460       break;
461     }
462     default: {}
463   }
464 }
CFWL_ComboBoxImp(const CFWL_WidgetImpProperties & properties,IFWL_Widget * pOuter)465 CFWL_ComboBoxImp::CFWL_ComboBoxImp(const CFWL_WidgetImpProperties& properties,
466                                    IFWL_Widget* pOuter)
467     : CFWL_WidgetImp(properties, pOuter),
468       m_pForm(NULL),
469       m_bLButtonDown(FALSE),
470       m_iCurSel(-1),
471       m_iBtnState(FWL_PARTSTATE_CMB_Normal),
472       m_fComboFormHandler(0),
473       m_bNeedShowList(FALSE) {
474   m_rtClient.Reset();
475   m_rtBtn.Reset();
476   m_rtHandler.Reset();
477 }
~CFWL_ComboBoxImp()478 CFWL_ComboBoxImp::~CFWL_ComboBoxImp() {
479 }
GetClassName(CFX_WideString & wsClass) const480 FWL_ERR CFWL_ComboBoxImp::GetClassName(CFX_WideString& wsClass) const {
481   wsClass = FWL_CLASS_ComboBox;
482   return FWL_ERR_Succeeded;
483 }
GetClassID() const484 FX_DWORD CFWL_ComboBoxImp::GetClassID() const {
485   return FWL_CLASSHASH_ComboBox;
486 }
Initialize()487 FWL_ERR CFWL_ComboBoxImp::Initialize() {
488   if (m_pWidgetMgr->IsFormDisabled()) {
489     return DisForm_Initialize();
490   }
491   if (CFWL_WidgetImp::Initialize() != FWL_ERR_Succeeded)
492     return FWL_WGTSTATE_Invisible;  // Probably a bug; not a FWL_ERR_ value.
493   m_pDelegate = new CFWL_ComboBoxImpDelegate(this);
494   CFWL_WidgetImpProperties prop;
495   prop.m_pThemeProvider = m_pProperties->m_pThemeProvider;
496   prop.m_dwStyles |= FWL_WGTSTYLE_Border | FWL_WGTSTYLE_VScroll;
497   if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_CMB_ListItemIconText) {
498     prop.m_dwStyleExes |= FWL_STYLEEXT_LTB_Icon;
499   }
500   prop.m_pDataProvider = m_pProperties->m_pDataProvider;
501   m_pListBox.reset(IFWL_ListBox::CreateComboList(prop, m_pInterface));
502   m_pListBox->Initialize();
503   if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_CMB_DropDown) && !m_pEdit) {
504     CFWL_WidgetImpProperties prop2;
505     m_pEdit.reset(IFWL_Edit::CreateComboEdit(prop2, m_pInterface));
506     m_pEdit->Initialize();
507     static_cast<CFWL_EditImp*>(m_pEdit->GetImpl())->SetOuter(m_pInterface);
508   }
509   if (m_pEdit) {
510     m_pEdit->SetParent(m_pInterface);
511   }
512   SetStates(m_pProperties->m_dwStates);
513   return FWL_ERR_Succeeded;
514 }
Finalize()515 FWL_ERR CFWL_ComboBoxImp::Finalize() {
516   if (m_pEdit) {
517     m_pEdit->Finalize();
518   }
519   m_pListBox->Finalize();
520   delete m_pDelegate;
521   m_pDelegate = nullptr;
522   return CFWL_WidgetImp::Finalize();
523 }
GetWidgetRect(CFX_RectF & rect,FX_BOOL bAutoSize)524 FWL_ERR CFWL_ComboBoxImp::GetWidgetRect(CFX_RectF& rect, FX_BOOL bAutoSize) {
525   if (bAutoSize) {
526     rect.Reset();
527     FX_BOOL bIsDropDown = IsDropDownStyle();
528     if (bIsDropDown && m_pEdit) {
529       m_pEdit->GetWidgetRect(rect, TRUE);
530     } else {
531       rect.width = 100;
532       rect.height = 16;
533     }
534     if (!m_pProperties->m_pThemeProvider) {
535       ReSetTheme();
536     }
537     FX_FLOAT* pFWidth = static_cast<FX_FLOAT*>(
538         GetThemeCapacity(FWL_WGTCAPACITY_ScrollBarWidth));
539     if (!pFWidth)
540       return FWL_ERR_Indefinite;
541     rect.Inflate(0, 0, *pFWidth, 0);
542     CFWL_WidgetImp::GetWidgetRect(rect, TRUE);
543   } else {
544     rect = m_pProperties->m_rtWidget;
545   }
546   return FWL_ERR_Succeeded;
547 }
ModifyStylesEx(FX_DWORD dwStylesExAdded,FX_DWORD dwStylesExRemoved)548 FWL_ERR CFWL_ComboBoxImp::ModifyStylesEx(FX_DWORD dwStylesExAdded,
549                                          FX_DWORD dwStylesExRemoved) {
550   if (m_pWidgetMgr->IsFormDisabled()) {
551     return DisForm_ModifyStylesEx(dwStylesExAdded, dwStylesExRemoved);
552   }
553   FX_BOOL bAddDropDown = dwStylesExAdded & FWL_STYLEEXT_CMB_DropDown;
554   FX_BOOL bRemoveDropDown = dwStylesExRemoved & FWL_STYLEEXT_CMB_DropDown;
555   if (bAddDropDown && !m_pEdit) {
556     CFWL_WidgetImpProperties prop;
557     m_pEdit.reset(IFWL_Edit::CreateComboEdit(prop, nullptr));
558     m_pEdit->Initialize();
559     static_cast<CFWL_EditImp*>(m_pEdit->GetImpl())->SetOuter(m_pInterface);
560     m_pEdit->SetParent(m_pInterface);
561   } else if (bRemoveDropDown && m_pEdit) {
562     m_pEdit->SetStates(FWL_WGTSTATE_Invisible, TRUE);
563   }
564   return CFWL_WidgetImp::ModifyStylesEx(dwStylesExAdded, dwStylesExRemoved);
565 }
Update()566 FWL_ERR CFWL_ComboBoxImp::Update() {
567   if (m_pWidgetMgr->IsFormDisabled()) {
568     return DisForm_Update();
569   }
570   if (IsLocked()) {
571     return FWL_ERR_Indefinite;
572   }
573   ReSetTheme();
574   FX_BOOL bDropDown = IsDropDownStyle();
575   if (bDropDown && m_pEdit) {
576     ReSetEditAlignment();
577   }
578   if (m_pProperties->m_pThemeProvider == NULL) {
579     m_pProperties->m_pThemeProvider = GetAvailableTheme();
580   }
581   Layout();
582   CFWL_ThemePart part;
583   part.m_pWidget = m_pInterface;
584   m_fComboFormHandler =
585       *static_cast<FX_FLOAT*>(m_pProperties->m_pThemeProvider->GetCapacity(
586           &part, FWL_WGTCAPACITY_CMB_ComboFormHandler));
587   return FWL_ERR_Succeeded;
588 }
HitTest(FX_FLOAT fx,FX_FLOAT fy)589 FX_DWORD CFWL_ComboBoxImp::HitTest(FX_FLOAT fx, FX_FLOAT fy) {
590   if (m_pWidgetMgr->IsFormDisabled()) {
591     return DisForm_HitTest(fx, fy);
592   }
593   return CFWL_WidgetImp::HitTest(fx, fy);
594 }
DrawWidget(CFX_Graphics * pGraphics,const CFX_Matrix * pMatrix)595 FWL_ERR CFWL_ComboBoxImp::DrawWidget(CFX_Graphics* pGraphics,
596                                      const CFX_Matrix* pMatrix) {
597   if (m_pWidgetMgr->IsFormDisabled()) {
598     return DisForm_DrawWidget(pGraphics, pMatrix);
599   }
600   if (!pGraphics)
601     return FWL_ERR_Indefinite;
602   if (!m_pProperties->m_pThemeProvider)
603     return FWL_ERR_Indefinite;
604   IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
605   FX_BOOL bIsDropDown = IsDropDownStyle();
606   if (HasBorder()) {
607     DrawBorder(pGraphics, FWL_PART_CMB_Border, pTheme, pMatrix);
608   }
609   if (HasEdge()) {
610     DrawEdge(pGraphics, FWL_PART_CMB_Edge, pTheme, pMatrix);
611   }
612   if (!bIsDropDown) {
613     CFX_RectF rtTextBk(m_rtClient);
614     rtTextBk.width -= m_rtBtn.width;
615     CFWL_ThemeBackground param;
616     param.m_pWidget = m_pInterface;
617     param.m_iPart = FWL_PART_CMB_Background;
618     param.m_pGraphics = pGraphics;
619     if (pMatrix) {
620       param.m_matrix.Concat(*pMatrix);
621     }
622     param.m_rtPart = rtTextBk;
623     if (m_iCurSel >= 0) {
624       IFWL_ListBoxDP* pData = static_cast<IFWL_ListBoxDP*>(
625           static_cast<CFWL_ComboListImp*>(m_pListBox->GetImpl())
626               ->m_pProperties->m_pDataProvider);
627       void* p = pData->GetItemData(m_pListBox.get(),
628                                    pData->GetItem(m_pListBox.get(), m_iCurSel));
629       if (p != NULL) {
630         param.m_pData = p;
631       }
632     }
633     if (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled) {
634       param.m_dwStates = FWL_PARTSTATE_CMB_Disabled;
635     } else if ((m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) &&
636                (m_iCurSel >= 0)) {
637       param.m_dwStates = FWL_PARTSTATE_CMB_Selected;
638     } else {
639       param.m_dwStates = FWL_PARTSTATE_CMB_Normal;
640     }
641     pTheme->DrawBackground(&param);
642     if (m_iCurSel >= 0) {
643       if (!m_pListBox)
644         return FWL_ERR_Indefinite;
645       CFX_WideString wsText;
646       IFWL_ComboBoxDP* pData =
647           static_cast<IFWL_ComboBoxDP*>(m_pProperties->m_pDataProvider);
648       FWL_HLISTITEM hItem = pData->GetItem(m_pInterface, m_iCurSel);
649       static_cast<CFWL_ComboListImp*>(m_pListBox->GetImpl())
650           ->GetItemText(hItem, wsText);
651       CFWL_ThemeText param;
652       param.m_pWidget = m_pInterface;
653       param.m_iPart = FWL_PART_CMB_Caption;
654       param.m_dwStates = m_iBtnState;
655       param.m_pGraphics = pGraphics;
656       param.m_matrix.Concat(*pMatrix);
657       param.m_rtPart = rtTextBk;
658       param.m_dwStates = (m_pProperties->m_dwStates & FWL_WGTSTATE_Focused)
659                              ? FWL_PARTSTATE_CMB_Selected
660                              : FWL_PARTSTATE_CMB_Normal;
661       param.m_wsText = wsText;
662       param.m_dwTTOStyles = FDE_TTOSTYLE_SingleLine;
663       param.m_iTTOAlign = FDE_TTOALIGNMENT_CenterLeft;
664       pTheme->DrawText(&param);
665     }
666   }
667   {
668     CFWL_ThemeBackground param;
669     param.m_pWidget = m_pInterface;
670     param.m_iPart = FWL_PART_CMB_DropDownButton;
671     param.m_dwStates = (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled)
672                            ? FWL_PARTSTATE_CMB_Disabled
673                            : m_iBtnState;
674     param.m_pGraphics = pGraphics;
675     param.m_matrix.Concat(*pMatrix);
676     param.m_rtPart = m_rtBtn;
677     pTheme->DrawBackground(&param);
678   }
679   return FWL_ERR_Succeeded;
680 }
SetThemeProvider(IFWL_ThemeProvider * pThemeProvider)681 FWL_ERR CFWL_ComboBoxImp::SetThemeProvider(IFWL_ThemeProvider* pThemeProvider) {
682   if (!pThemeProvider)
683     return FWL_ERR_Indefinite;
684   m_pProperties->m_pThemeProvider = pThemeProvider;
685   if (m_pListBox && pThemeProvider->IsValidWidget(m_pListBox.get())) {
686     m_pListBox->SetThemeProvider(pThemeProvider);
687   }
688   if (m_pEdit && pThemeProvider->IsValidWidget(m_pEdit.get())) {
689     m_pEdit->SetThemeProvider(pThemeProvider);
690   }
691   return FWL_ERR_Succeeded;
692 }
GetCurSel()693 int32_t CFWL_ComboBoxImp::GetCurSel() {
694   return m_iCurSel;
695 }
SetCurSel(int32_t iSel)696 FWL_ERR CFWL_ComboBoxImp::SetCurSel(int32_t iSel) {
697   int32_t iCount =
698       static_cast<CFWL_ComboListImp*>(m_pListBox->GetImpl())->CountItems();
699   FX_BOOL bClearSel = iSel < 0 || iSel >= iCount;
700   FX_BOOL bDropDown = IsDropDownStyle();
701   if (bDropDown && m_pEdit) {
702     if (bClearSel) {
703       m_pEdit->SetText(CFX_WideString());
704     } else {
705       CFX_WideString wsText;
706       IFWL_ComboBoxDP* pData =
707           static_cast<IFWL_ComboBoxDP*>(m_pProperties->m_pDataProvider);
708       FWL_HLISTITEM hItem = pData->GetItem(m_pInterface, iSel);
709       static_cast<CFWL_ComboListImp*>(m_pListBox->GetImpl())
710           ->GetItemText(hItem, wsText);
711       m_pEdit->SetText(wsText);
712     }
713     m_pEdit->Update();
714   }
715   m_iCurSel = bClearSel ? -1 : iSel;
716   return FWL_ERR_Succeeded;
717 }
SetStates(FX_DWORD dwStates,FX_BOOL bSet)718 FWL_ERR CFWL_ComboBoxImp::SetStates(FX_DWORD dwStates, FX_BOOL bSet) {
719   FX_BOOL bIsDropDown = IsDropDownStyle();
720   if (bIsDropDown && m_pEdit) {
721     m_pEdit->SetStates(dwStates, bSet);
722   }
723   if (m_pListBox) {
724     m_pListBox->SetStates(dwStates, bSet);
725   }
726   return CFWL_WidgetImp::SetStates(dwStates, bSet);
727 }
SetEditText(const CFX_WideString & wsText)728 FWL_ERR CFWL_ComboBoxImp::SetEditText(const CFX_WideString& wsText) {
729   if (!m_pEdit)
730     return FWL_ERR_Indefinite;
731   m_pEdit->SetText(wsText);
732   return m_pEdit->Update();
733 }
GetEditTextLength() const734 int32_t CFWL_ComboBoxImp::GetEditTextLength() const {
735   if (!m_pEdit)
736     return -1;
737   return m_pEdit->GetTextLength();
738 }
GetEditText(CFX_WideString & wsText,int32_t nStart,int32_t nCount) const739 FWL_ERR CFWL_ComboBoxImp::GetEditText(CFX_WideString& wsText,
740                                       int32_t nStart,
741                                       int32_t nCount) const {
742   if (m_pEdit) {
743     return m_pEdit->GetText(wsText, nStart, nCount);
744   } else if (m_pListBox) {
745     IFWL_ComboBoxDP* pData =
746         static_cast<IFWL_ComboBoxDP*>(m_pProperties->m_pDataProvider);
747     FWL_HLISTITEM hItem = pData->GetItem(m_pInterface, m_iCurSel);
748     return m_pListBox->GetItemText(hItem, wsText);
749   }
750   return FWL_ERR_Indefinite;
751 }
SetEditSelRange(int32_t nStart,int32_t nCount)752 FWL_ERR CFWL_ComboBoxImp::SetEditSelRange(int32_t nStart, int32_t nCount) {
753   if (!m_pEdit)
754     return FWL_ERR_Indefinite;
755   static_cast<CFWL_ComboEditImp*>(m_pEdit->GetImpl())->ClearSelected();
756   m_pEdit->AddSelRange(nStart, nCount);
757   return FWL_ERR_Succeeded;
758 }
GetEditSelRange(int32_t nIndex,int32_t & nStart)759 int32_t CFWL_ComboBoxImp::GetEditSelRange(int32_t nIndex, int32_t& nStart) {
760   if (!m_pEdit)
761     return -1;
762   return m_pEdit->GetSelRange(nIndex, nStart);
763 }
GetEditLimit()764 int32_t CFWL_ComboBoxImp::GetEditLimit() {
765   if (!m_pEdit)
766     return -1;
767   return m_pEdit->GetLimit();
768 }
SetEditLimit(int32_t nLimit)769 FWL_ERR CFWL_ComboBoxImp::SetEditLimit(int32_t nLimit) {
770   if (!m_pEdit)
771     return FWL_ERR_Indefinite;
772   return m_pEdit->SetLimit(nLimit);
773 }
EditDoClipboard(int32_t iCmd)774 FWL_ERR CFWL_ComboBoxImp::EditDoClipboard(int32_t iCmd) {
775   if (!m_pEdit)
776     return FWL_ERR_Indefinite;
777   return m_pEdit->DoClipboard(iCmd);
778 }
EditRedo(const CFX_ByteStringC & bsRecord)779 FX_BOOL CFWL_ComboBoxImp::EditRedo(const CFX_ByteStringC& bsRecord) {
780   if (!m_pEdit)
781     return FALSE;
782   return m_pEdit->Redo(bsRecord);
783 }
EditUndo(const CFX_ByteStringC & bsRecord)784 FX_BOOL CFWL_ComboBoxImp::EditUndo(const CFX_ByteStringC& bsRecord) {
785   if (!m_pEdit)
786     return FALSE;
787   return m_pEdit->Undo(bsRecord);
788 }
GetListBoxt()789 IFWL_ListBox* CFWL_ComboBoxImp::GetListBoxt() {
790   return m_pListBox.get();
791 }
AfterFocusShowDropList()792 FX_BOOL CFWL_ComboBoxImp::AfterFocusShowDropList() {
793   if (!m_bNeedShowList) {
794     return FALSE;
795   }
796   if (m_pEdit) {
797     MatchEditText();
798   }
799   ShowDropList(TRUE);
800   m_bNeedShowList = FALSE;
801   return TRUE;
802 }
OpenDropDownList(FX_BOOL bActivate)803 FX_ERR CFWL_ComboBoxImp::OpenDropDownList(FX_BOOL bActivate) {
804   ShowDropList(bActivate);
805   return FWL_ERR_Succeeded;
806 }
EditCanUndo()807 FX_BOOL CFWL_ComboBoxImp::EditCanUndo() {
808   return m_pEdit->CanUndo();
809 }
EditCanRedo()810 FX_BOOL CFWL_ComboBoxImp::EditCanRedo() {
811   return m_pEdit->CanRedo();
812 }
EditUndo()813 FX_BOOL CFWL_ComboBoxImp::EditUndo() {
814   return m_pEdit->Undo();
815 }
EditRedo()816 FX_BOOL CFWL_ComboBoxImp::EditRedo() {
817   return m_pEdit->Redo();
818 }
EditCanCopy()819 FX_BOOL CFWL_ComboBoxImp::EditCanCopy() {
820   return m_pEdit->CountSelRanges() > 0;
821 }
EditCanCut()822 FX_BOOL CFWL_ComboBoxImp::EditCanCut() {
823   if (m_pEdit->GetStylesEx() & FWL_STYLEEXT_EDT_ReadOnly) {
824     return FALSE;
825   }
826   return m_pEdit->CountSelRanges() > 0;
827 }
EditCanSelectAll()828 FX_BOOL CFWL_ComboBoxImp::EditCanSelectAll() {
829   return m_pEdit->GetTextLength() > 0;
830 }
EditCopy(CFX_WideString & wsCopy)831 FX_BOOL CFWL_ComboBoxImp::EditCopy(CFX_WideString& wsCopy) {
832   return m_pEdit->Copy(wsCopy);
833 }
EditCut(CFX_WideString & wsCut)834 FX_BOOL CFWL_ComboBoxImp::EditCut(CFX_WideString& wsCut) {
835   return m_pEdit->Cut(wsCut);
836 }
EditPaste(const CFX_WideString & wsPaste)837 FX_BOOL CFWL_ComboBoxImp::EditPaste(const CFX_WideString& wsPaste) {
838   return m_pEdit->Paste(wsPaste);
839 }
EditSelectAll()840 FX_BOOL CFWL_ComboBoxImp::EditSelectAll() {
841   return m_pEdit->AddSelRange(0) == FWL_ERR_Succeeded;
842 }
EditDelete()843 FX_BOOL CFWL_ComboBoxImp::EditDelete() {
844   return m_pEdit->ClearText() == FWL_ERR_Succeeded;
845 }
EditDeSelect()846 FX_BOOL CFWL_ComboBoxImp::EditDeSelect() {
847   return m_pEdit->ClearSelections() == FWL_ERR_Succeeded;
848 }
GetBBox(CFX_RectF & rect)849 FWL_ERR CFWL_ComboBoxImp::GetBBox(CFX_RectF& rect) {
850   if (m_pWidgetMgr->IsFormDisabled()) {
851     return DisForm_GetBBox(rect);
852   }
853   rect = m_pProperties->m_rtWidget;
854   if (m_pListBox && IsDropListShowed()) {
855     CFX_RectF rtList;
856     m_pListBox->GetWidgetRect(rtList);
857     rtList.Offset(rect.left, rect.top);
858     rect.Union(rtList);
859   }
860   return FWL_ERR_Succeeded;
861 }
EditModifyStylesEx(FX_DWORD dwStylesExAdded,FX_DWORD dwStylesExRemoved)862 FWL_ERR CFWL_ComboBoxImp::EditModifyStylesEx(FX_DWORD dwStylesExAdded,
863                                              FX_DWORD dwStylesExRemoved) {
864   if (m_pEdit != NULL) {
865     return m_pEdit->ModifyStylesEx(dwStylesExAdded, dwStylesExRemoved);
866   } else {
867     return FWL_ERR_Parameter_Invalid;
868   }
869 }
GetListHeight()870 FX_FLOAT CFWL_ComboBoxImp::GetListHeight() {
871   return static_cast<IFWL_ComboBoxDP*>(m_pProperties->m_pDataProvider)
872       ->GetListHeight(m_pInterface);
873 }
DrawStretchHandler(CFX_Graphics * pGraphics,const CFX_Matrix * pMatrix)874 void CFWL_ComboBoxImp::DrawStretchHandler(CFX_Graphics* pGraphics,
875                                           const CFX_Matrix* pMatrix) {
876   CFWL_ThemeBackground param;
877   param.m_pGraphics = pGraphics;
878   param.m_iPart = FWL_PART_CMB_StretcgHandler;
879   param.m_dwStates = FWL_PARTSTATE_CMB_Normal;
880   param.m_pWidget = m_pInterface;
881   if (pMatrix) {
882     param.m_matrix.Concat(*pMatrix);
883   }
884   param.m_rtPart = m_rtHandler;
885   m_pProperties->m_pThemeProvider->DrawBackground(&param);
886 }
ShowDropList(FX_BOOL bActivate)887 void CFWL_ComboBoxImp::ShowDropList(FX_BOOL bActivate) {
888   if (m_pWidgetMgr->IsFormDisabled()) {
889     return DisForm_ShowDropList(bActivate);
890   }
891   FX_BOOL bDropList = IsDropListShowed();
892   if (bDropList == bActivate) {
893     return;
894   }
895   if (!m_pForm) {
896     InitProxyForm();
897   }
898   m_pListProxyDelegate->Reset();
899   if (bActivate) {
900     static_cast<CFWL_ComboListImp*>(m_pListBox->GetImpl())
901         ->ChangeSelected(m_iCurSel);
902     ReSetListItemAlignment();
903     FX_DWORD dwStyleAdd = m_pProperties->m_dwStyleExes &
904                           (FWL_STYLEEXT_CMB_Sort | FWL_STYLEEXT_CMB_OwnerDraw);
905     m_pListBox->ModifyStylesEx(dwStyleAdd, 0);
906     m_pListBox->GetWidgetRect(m_rtList, TRUE);
907     FX_FLOAT fHeight = GetListHeight();
908     if (fHeight > 0) {
909       if (m_rtList.height > GetListHeight()) {
910         m_rtList.height = GetListHeight();
911         m_pListBox->ModifyStyles(FWL_WGTSTYLE_VScroll, 0);
912       }
913     }
914     CFX_RectF rtAnchor;
915     rtAnchor.Set(0, 0, m_pProperties->m_rtWidget.width,
916                  m_pProperties->m_rtWidget.height);
917     FX_FLOAT fMinHeight = 0;
918     if (m_rtList.width < m_rtClient.width) {
919       m_rtList.width = m_rtClient.width;
920     }
921     m_rtProxy = m_rtList;
922     if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_CMB_ListDrag) {
923       m_rtProxy.height += m_fComboFormHandler;
924     }
925     GetPopupPos(fMinHeight, m_rtProxy.height, rtAnchor, m_rtProxy);
926     if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_CMB_ListDrag) {
927       FX_FLOAT fx = 0;
928       FX_FLOAT fy = m_rtClient.top + m_rtClient.height / 2;
929       TransformTo(NULL, fx, fy);
930       m_bUpFormHandler = fy > m_rtProxy.top;
931       if (m_bUpFormHandler) {
932         m_rtHandler.Set(0, 0, m_rtList.width, m_fComboFormHandler);
933         m_rtList.top = m_fComboFormHandler;
934       } else {
935         m_rtHandler.Set(0, m_rtList.height, m_rtList.width,
936                         m_fComboFormHandler);
937       }
938     }
939     m_pForm->SetWidgetRect(m_rtProxy);
940     m_pForm->Update();
941     m_pListBox->SetWidgetRect(m_rtList);
942     m_pListBox->Update();
943     CFWL_EvtCmbPreDropDown ev;
944     ev.m_pSrcTarget = m_pInterface;
945     DispatchEvent(&ev);
946     m_fItemHeight =
947         static_cast<CFWL_ComboListImp*>(m_pListBox->GetImpl())->m_fItemHeight;
948     static_cast<CFWL_ComboListImp*>(m_pListBox->GetImpl())->SetFocus(TRUE);
949     m_pForm->DoModal();
950     static_cast<CFWL_ComboListImp*>(m_pListBox->GetImpl())->SetFocus(FALSE);
951   } else {
952     m_pForm->EndDoModal();
953     CFWL_EvtCmbCloseUp ev;
954     ev.m_pSrcTarget = m_pInterface;
955     DispatchEvent(&ev);
956     m_bLButtonDown = FALSE;
957     static_cast<CFWL_ComboListImp*>(m_pListBox->GetImpl())->m_bNotifyOwner =
958         TRUE;
959     SetFocus(TRUE);
960   }
961 }
IsDropListShowed()962 FX_BOOL CFWL_ComboBoxImp::IsDropListShowed() {
963   return m_pForm && !(m_pForm->GetStates() & FWL_WGTSTATE_Invisible);
964 }
IsDropDownStyle() const965 FX_BOOL CFWL_ComboBoxImp::IsDropDownStyle() const {
966   return m_pProperties->m_dwStyleExes & FWL_STYLEEXT_CMB_DropDown;
967 }
MatchEditText()968 void CFWL_ComboBoxImp::MatchEditText() {
969   CFX_WideString wsText;
970   m_pEdit->GetText(wsText);
971   int32_t iMatch =
972       static_cast<CFWL_ComboListImp*>(m_pListBox->GetImpl())->MatchItem(wsText);
973   if (iMatch != m_iCurSel) {
974     static_cast<CFWL_ComboListImp*>(m_pListBox->GetImpl())
975         ->ChangeSelected(iMatch);
976     if (iMatch >= 0) {
977       SynchrEditText(iMatch);
978     }
979   } else if (iMatch >= 0) {
980     static_cast<CFWL_ComboEditImp*>(m_pEdit->GetImpl())->SetSelected();
981   }
982   m_iCurSel = iMatch;
983 }
SynchrEditText(int32_t iListItem)984 void CFWL_ComboBoxImp::SynchrEditText(int32_t iListItem) {
985   CFX_WideString wsText;
986   IFWL_ComboBoxDP* pData =
987       static_cast<IFWL_ComboBoxDP*>(m_pProperties->m_pDataProvider);
988   FWL_HLISTITEM hItem = pData->GetItem(m_pInterface, iListItem);
989   static_cast<CFWL_ComboListImp*>(m_pListBox->GetImpl())
990       ->GetItemText(hItem, wsText);
991   m_pEdit->SetText(wsText);
992   m_pEdit->Update();
993   static_cast<CFWL_ComboEditImp*>(m_pEdit->GetImpl())->SetSelected();
994 }
Layout()995 void CFWL_ComboBoxImp::Layout() {
996   if (m_pWidgetMgr->IsFormDisabled()) {
997     return DisForm_Layout();
998   }
999   GetClientRect(m_rtClient);
1000   FX_FLOAT* pFWidth =
1001       static_cast<FX_FLOAT*>(GetThemeCapacity(FWL_WGTCAPACITY_ScrollBarWidth));
1002   if (!pFWidth)
1003     return;
1004   FX_FLOAT fBtn = *pFWidth;
1005   m_rtBtn.Set(m_rtClient.right() - fBtn, m_rtClient.top, fBtn,
1006               m_rtClient.height);
1007   FX_BOOL bIsDropDown = IsDropDownStyle();
1008   if (bIsDropDown && m_pEdit) {
1009     CFX_RectF rtEdit;
1010     rtEdit.Set(m_rtClient.left, m_rtClient.top, m_rtClient.width - fBtn,
1011                m_rtClient.height);
1012     m_pEdit->SetWidgetRect(rtEdit);
1013     if (m_iCurSel >= 0) {
1014       CFX_WideString wsText;
1015       IFWL_ComboBoxDP* pData =
1016           static_cast<IFWL_ComboBoxDP*>(m_pProperties->m_pDataProvider);
1017       FWL_HLISTITEM hItem = pData->GetItem(m_pInterface, m_iCurSel);
1018       static_cast<CFWL_ComboListImp*>(m_pListBox->GetImpl())
1019           ->GetItemText(hItem, wsText);
1020       m_pEdit->LockUpdate();
1021       m_pEdit->SetText(wsText);
1022       m_pEdit->UnlockUpdate();
1023     }
1024     m_pEdit->Update();
1025   }
1026 }
ReSetTheme()1027 void CFWL_ComboBoxImp::ReSetTheme() {
1028   IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
1029   if (!pTheme) {
1030     pTheme = GetAvailableTheme();
1031     m_pProperties->m_pThemeProvider = pTheme;
1032   }
1033   if (m_pListBox) {
1034     if (!m_pListBox->GetThemeProvider() &&
1035         pTheme->IsValidWidget(m_pListBox.get())) {
1036       m_pListBox->SetThemeProvider(pTheme);
1037     }
1038   }
1039   if (m_pEdit) {
1040     if (!m_pEdit->GetThemeProvider() && pTheme->IsValidWidget(m_pEdit.get())) {
1041       m_pEdit->SetThemeProvider(pTheme);
1042     }
1043   }
1044 }
ReSetEditAlignment()1045 void CFWL_ComboBoxImp::ReSetEditAlignment() {
1046   if (!m_pEdit)
1047     return;
1048   FX_DWORD dwStylExes = m_pProperties->m_dwStyleExes;
1049   FX_DWORD dwAdd = 0;
1050   switch (dwStylExes & FWL_STYLEEXT_CMB_EditHAlignMask) {
1051     case FWL_STYLEEXT_CMB_EditHCenter: {
1052       dwAdd |= FWL_STYLEEXT_EDT_HCenter;
1053       break;
1054     }
1055     case FWL_STYLEEXT_CMB_EditHFar: {
1056       dwAdd |= FWL_STYLEEXT_EDT_HFar;
1057       break;
1058     }
1059     default: { dwAdd |= FWL_STYLEEXT_EDT_HNear; }
1060   }
1061   switch (dwStylExes & FWL_STYLEEXT_CMB_EditVAlignMask) {
1062     case FWL_STYLEEXT_CMB_EditVCenter: {
1063       dwAdd |= FWL_STYLEEXT_EDT_VCenter;
1064       break;
1065     }
1066     case FWL_STYLEEXT_CMB_EditVFar: {
1067       dwAdd |= FWL_STYLEEXT_EDT_VFar;
1068       break;
1069     }
1070     default: { dwAdd |= FWL_STYLEEXT_EDT_VNear; }
1071   }
1072   if (dwStylExes & FWL_STYLEEXT_CMB_EditJustified) {
1073     dwAdd |= FWL_STYLEEXT_EDT_Justified;
1074   }
1075   if (dwStylExes & FWL_STYLEEXT_CMB_EditDistributed) {
1076     dwAdd |= FWL_STYLEEXT_EDT_Distributed;
1077   }
1078   m_pEdit->ModifyStylesEx(dwAdd, FWL_STYLEEXT_EDT_HAlignMask |
1079                                      FWL_STYLEEXT_EDT_HAlignModeMask |
1080                                      FWL_STYLEEXT_EDT_VAlignMask);
1081 }
ReSetListItemAlignment()1082 void CFWL_ComboBoxImp::ReSetListItemAlignment() {
1083   if (!m_pListBox)
1084     return;
1085   FX_DWORD dwStylExes = m_pProperties->m_dwStyleExes;
1086   FX_DWORD dwAdd = 0;
1087   switch (dwStylExes & FWL_STYLEEXT_CMB_ListItemAlignMask) {
1088     case FWL_STYLEEXT_CMB_ListItemCenterAlign: {
1089       dwAdd |= FWL_STYLEEXT_LTB_CenterAlign;
1090     }
1091     case FWL_STYLEEXT_CMB_ListItemRightAlign: {
1092       dwAdd |= FWL_STYLEEXT_LTB_RightAlign;
1093     }
1094     default: { dwAdd |= FWL_STYLEEXT_LTB_LeftAlign; }
1095   }
1096   m_pListBox->ModifyStylesEx(dwAdd, FWL_STYLEEXT_CMB_ListItemAlignMask);
1097 }
ProcessSelChanged(FX_BOOL bLButtonUp)1098 void CFWL_ComboBoxImp::ProcessSelChanged(FX_BOOL bLButtonUp) {
1099   IFWL_ComboBoxDP* pDatas =
1100       static_cast<IFWL_ComboBoxDP*>(m_pProperties->m_pDataProvider);
1101   m_iCurSel = pDatas->GetItemIndex(m_pInterface, m_pListBox->GetSelItem(0));
1102   FX_BOOL bDropDown = IsDropDownStyle();
1103   if (bDropDown) {
1104     IFWL_ComboBoxDP* pData =
1105         static_cast<IFWL_ComboBoxDP*>(m_pProperties->m_pDataProvider);
1106     FWL_HLISTITEM hItem = pData->GetItem(m_pInterface, m_iCurSel);
1107     if (hItem) {
1108       CFX_WideString wsText;
1109       pData->GetItemText(m_pInterface, hItem, wsText);
1110       if (m_pEdit) {
1111         m_pEdit->SetText(wsText);
1112         m_pEdit->Update();
1113         static_cast<CFWL_ComboEditImp*>(m_pEdit->GetImpl())->SetSelected();
1114       }
1115       CFWL_EvtCmbSelChanged ev;
1116       ev.bLButtonUp = bLButtonUp;
1117       ev.m_pSrcTarget = m_pInterface;
1118       ev.iArraySels.Add(m_iCurSel);
1119       DispatchEvent(&ev);
1120     }
1121   } else {
1122     Repaint(&m_rtClient);
1123   }
1124 }
InitProxyForm()1125 void CFWL_ComboBoxImp::InitProxyForm() {
1126   if (m_pForm)
1127     return;
1128   if (!m_pListBox)
1129     return;
1130   CFWL_WidgetImpProperties propForm;
1131   propForm.m_pOwner = m_pInterface;
1132   propForm.m_dwStyles = FWL_WGTSTYLE_Popup;
1133   propForm.m_dwStates = FWL_WGTSTATE_Invisible;
1134   CFX_WideString className;
1135   m_pForm = IFWL_Form::CreateFormProxy(propForm, &className, m_pListBox.get());
1136   m_pForm->Initialize();
1137   m_pProxy = static_cast<CFWL_FormProxyImp*>(m_pForm->GetImpl());
1138   m_pListBox->SetParent(m_pForm);
1139   m_pListProxyDelegate = new CFWL_ComboProxyImpDelegate(m_pForm, this);
1140   m_pProxy->SetDelegate(m_pListProxyDelegate);
1141 }
DisForm_Initialize()1142 FWL_ERR CFWL_ComboBoxImp::DisForm_Initialize() {
1143   if (CFWL_WidgetImp::Initialize() != FWL_ERR_Succeeded)
1144     return FWL_WGTSTATE_Invisible;  // Ditto.
1145   m_pDelegate = new CFWL_ComboBoxImpDelegate(this);
1146   DisForm_InitComboList();
1147   DisForm_InitComboEdit();
1148   return FWL_ERR_Succeeded;
1149 }
DisForm_InitComboList()1150 void CFWL_ComboBoxImp::DisForm_InitComboList() {
1151   if (m_pListBox) {
1152     return;
1153   }
1154   CFWL_WidgetImpProperties prop;
1155   prop.m_pParent = m_pInterface;
1156   prop.m_dwStyles = FWL_WGTSTYLE_Border | FWL_WGTSTYLE_VScroll;
1157   prop.m_dwStates = FWL_WGTSTATE_Invisible;
1158   prop.m_pDataProvider = m_pProperties->m_pDataProvider;
1159   prop.m_pThemeProvider = m_pProperties->m_pThemeProvider;
1160   m_pListBox.reset(IFWL_ListBox::CreateComboList(prop, m_pInterface));
1161   m_pListBox->Initialize();
1162 }
DisForm_InitComboEdit()1163 void CFWL_ComboBoxImp::DisForm_InitComboEdit() {
1164   if (m_pEdit) {
1165     return;
1166   }
1167   CFWL_WidgetImpProperties prop;
1168   prop.m_pParent = m_pInterface;
1169   prop.m_pThemeProvider = m_pProperties->m_pThemeProvider;
1170   m_pEdit.reset(IFWL_Edit::CreateComboEdit(prop, m_pInterface));
1171   m_pEdit->Initialize();
1172   static_cast<CFWL_ComboEditImp*>(m_pEdit->GetImpl())->SetOuter(m_pInterface);
1173 }
DisForm_ShowDropList(FX_BOOL bActivate)1174 void CFWL_ComboBoxImp::DisForm_ShowDropList(FX_BOOL bActivate) {
1175   FX_BOOL bDropList = DisForm_IsDropListShowed();
1176   if (bDropList == bActivate) {
1177     return;
1178   }
1179   if (bActivate) {
1180     CFWL_EvtCmbPreDropDown preEvent;
1181     preEvent.m_pSrcTarget = m_pInterface;
1182     DispatchEvent(&preEvent);
1183     CFWL_ComboListImp* pComboList =
1184         static_cast<CFWL_ComboListImp*>(m_pListBox->GetImpl());
1185     int32_t iItems = pComboList->CountItems();
1186     if (iItems < 1) {
1187       return;
1188     }
1189     ReSetListItemAlignment();
1190     pComboList->ChangeSelected(m_iCurSel);
1191     FX_FLOAT fItemHeight = pComboList->GetItemHeigt();
1192     FX_FLOAT fBorder = GetBorderSize();
1193     FX_FLOAT fPopupMin = 0.0f;
1194     if (iItems > 3) {
1195       fPopupMin = fItemHeight * 3 + fBorder * 2;
1196     }
1197     FX_FLOAT fPopupMax = fItemHeight * iItems + fBorder * 2;
1198     CFX_RectF rtList;
1199     rtList.left = m_rtClient.left;
1200     rtList.width = m_pProperties->m_rtWidget.width;
1201     rtList.top = 0;
1202     rtList.height = 0;
1203     GetPopupPos(fPopupMin, fPopupMax, m_pProperties->m_rtWidget, rtList);
1204     m_pListBox->SetWidgetRect(rtList);
1205     m_pListBox->Update();
1206   } else {
1207     SetFocus(TRUE);
1208   }
1209   m_pListBox->SetStates(FWL_WGTSTATE_Invisible, !bActivate);
1210   if (bActivate) {
1211     CFWL_EvtCmbPostDropDown postEvent;
1212     postEvent.m_pSrcTarget = m_pInterface;
1213     DispatchEvent(&postEvent);
1214   }
1215   CFX_RectF rect;
1216   m_pListBox->GetWidgetRect(rect);
1217   rect.Inflate(2, 2);
1218   Repaint(&rect);
1219 }
DisForm_IsDropListShowed()1220 FX_BOOL CFWL_ComboBoxImp::DisForm_IsDropListShowed() {
1221   return !(m_pListBox->GetStates() & FWL_WGTSTATE_Invisible);
1222 }
DisForm_ModifyStylesEx(FX_DWORD dwStylesExAdded,FX_DWORD dwStylesExRemoved)1223 FWL_ERR CFWL_ComboBoxImp::DisForm_ModifyStylesEx(FX_DWORD dwStylesExAdded,
1224                                                  FX_DWORD dwStylesExRemoved) {
1225   if (!m_pEdit) {
1226     DisForm_InitComboEdit();
1227   }
1228   FX_BOOL bAddDropDown = dwStylesExAdded & FWL_STYLEEXT_CMB_DropDown;
1229   FX_BOOL bDelDropDown = dwStylesExRemoved & FWL_STYLEEXT_CMB_DropDown;
1230   dwStylesExRemoved &= ~FWL_STYLEEXT_CMB_DropDown;
1231   m_pProperties->m_dwStyleExes |= FWL_STYLEEXT_CMB_DropDown;
1232   if (bAddDropDown) {
1233     m_pEdit->ModifyStylesEx(0, FWL_STYLEEXT_EDT_ReadOnly);
1234   } else if (bDelDropDown) {
1235     m_pEdit->ModifyStylesEx(FWL_STYLEEXT_EDT_ReadOnly, 0);
1236   }
1237   return CFWL_WidgetImp::ModifyStylesEx(dwStylesExAdded, dwStylesExRemoved);
1238 }
DisForm_Update()1239 FWL_ERR CFWL_ComboBoxImp::DisForm_Update() {
1240   if (m_iLock) {
1241     return FWL_ERR_Indefinite;
1242   }
1243   if (m_pEdit) {
1244     ReSetEditAlignment();
1245   }
1246   ReSetTheme();
1247   Layout();
1248   return FWL_ERR_Succeeded;
1249 }
DisForm_HitTest(FX_FLOAT fx,FX_FLOAT fy)1250 FX_DWORD CFWL_ComboBoxImp::DisForm_HitTest(FX_FLOAT fx, FX_FLOAT fy) {
1251   CFX_RectF rect;
1252   rect.Set(0, 0, m_pProperties->m_rtWidget.width - m_rtBtn.width,
1253            m_pProperties->m_rtWidget.height);
1254   if (rect.Contains(fx, fy)) {
1255     return FWL_WGTHITTEST_Edit;
1256   }
1257   if (m_rtBtn.Contains(fx, fy)) {
1258     return FWL_WGTHITTEST_Client;
1259   }
1260   if (DisForm_IsDropListShowed()) {
1261     m_pListBox->GetWidgetRect(rect);
1262     if (rect.Contains(fx, fy)) {
1263       return FWL_WGTHITTEST_Client;
1264     }
1265   }
1266   return FWL_WGTHITTEST_Unknown;
1267 }
DisForm_DrawWidget(CFX_Graphics * pGraphics,const CFX_Matrix * pMatrix)1268 FWL_ERR CFWL_ComboBoxImp::DisForm_DrawWidget(CFX_Graphics* pGraphics,
1269                                              const CFX_Matrix* pMatrix) {
1270   IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
1271   CFX_Matrix mtOrg;
1272   mtOrg.Set(1, 0, 0, 1, 0, 0);
1273   if (pMatrix) {
1274     mtOrg = *pMatrix;
1275   }
1276   FX_BOOL bListShowed = m_pListBox && DisForm_IsDropListShowed();
1277   pGraphics->SaveGraphState();
1278   pGraphics->ConcatMatrix(&mtOrg);
1279   if (!m_rtBtn.IsEmpty(0.1f)) {
1280     CFWL_ThemeBackground param;
1281     param.m_pWidget = m_pInterface;
1282     param.m_iPart = FWL_PART_CMB_DropDownButton;
1283     param.m_dwStates = m_iBtnState;
1284     param.m_pGraphics = pGraphics;
1285     param.m_rtPart = m_rtBtn;
1286     pTheme->DrawBackground(&param);
1287   }
1288   pGraphics->RestoreGraphState();
1289   if (m_pEdit) {
1290     CFX_RectF rtEdit;
1291     m_pEdit->GetWidgetRect(rtEdit);
1292     CFX_Matrix mt;
1293     mt.Set(1, 0, 0, 1, rtEdit.left, rtEdit.top);
1294     mt.Concat(mtOrg);
1295     m_pEdit->DrawWidget(pGraphics, &mt);
1296   }
1297   if (bListShowed) {
1298     CFX_RectF rtList;
1299     m_pListBox->GetWidgetRect(rtList);
1300     CFX_Matrix mt;
1301     mt.Set(1, 0, 0, 1, rtList.left, rtList.top);
1302     mt.Concat(mtOrg);
1303     m_pListBox->DrawWidget(pGraphics, &mt);
1304   }
1305   return FWL_ERR_Succeeded;
1306 }
DisForm_GetBBox(CFX_RectF & rect)1307 FWL_ERR CFWL_ComboBoxImp::DisForm_GetBBox(CFX_RectF& rect) {
1308   rect = m_pProperties->m_rtWidget;
1309   if (m_pListBox && DisForm_IsDropListShowed()) {
1310     CFX_RectF rtList;
1311     m_pListBox->GetWidgetRect(rtList);
1312     rtList.Offset(rect.left, rect.top);
1313     rect.Union(rtList);
1314   }
1315   return FWL_ERR_Succeeded;
1316 }
DisForm_Layout()1317 void CFWL_ComboBoxImp::DisForm_Layout() {
1318   GetClientRect(m_rtClient);
1319   m_rtContent = m_rtClient;
1320   FX_FLOAT* pFWidth =
1321       static_cast<FX_FLOAT*>(GetThemeCapacity(FWL_WGTCAPACITY_ScrollBarWidth));
1322   if (!pFWidth)
1323     return;
1324   FX_FLOAT borderWidth = 0;
1325   { borderWidth = FWL_PART_CMB_Border; }
1326   FX_FLOAT fBtn = *pFWidth;
1327   if (!(this->GetStylesEx() & FWL_STYLEEXT_CMB_ReadOnly)) {
1328     m_rtBtn.Set(m_rtClient.right() - fBtn, m_rtClient.top + borderWidth,
1329                 fBtn - borderWidth, m_rtClient.height - 2 * borderWidth);
1330   }
1331   CFX_RectF* pUIMargin =
1332       static_cast<CFX_RectF*>(GetThemeCapacity(FWL_WGTCAPACITY_UIMargin));
1333   if (pUIMargin) {
1334     m_rtContent.Deflate(pUIMargin->left, pUIMargin->top, pUIMargin->width,
1335                         pUIMargin->height);
1336   }
1337   FX_BOOL bIsDropDown = IsDropDownStyle();
1338   if (bIsDropDown && m_pEdit) {
1339     CFX_RectF rtEdit;
1340     rtEdit.Set(m_rtContent.left, m_rtContent.top, m_rtContent.width - fBtn,
1341                m_rtContent.height);
1342     m_pEdit->SetWidgetRect(rtEdit);
1343     if (m_iCurSel >= 0) {
1344       CFX_WideString wsText;
1345       IFWL_ComboBoxDP* pData =
1346           static_cast<IFWL_ComboBoxDP*>(m_pProperties->m_pDataProvider);
1347       FWL_HLISTITEM hItem = pData->GetItem(m_pInterface, m_iCurSel);
1348       static_cast<CFWL_ComboListImp*>(m_pListBox->GetImpl())
1349           ->GetItemText(hItem, wsText);
1350       m_pEdit->LockUpdate();
1351       m_pEdit->SetText(wsText);
1352       m_pEdit->UnlockUpdate();
1353     }
1354     m_pEdit->Update();
1355   }
1356 }
CFWL_ComboBoxImpDelegate(CFWL_ComboBoxImp * pOwner)1357 CFWL_ComboBoxImpDelegate::CFWL_ComboBoxImpDelegate(CFWL_ComboBoxImp* pOwner)
1358     : m_pOwner(pOwner) {}
OnProcessMessage(CFWL_Message * pMessage)1359 int32_t CFWL_ComboBoxImpDelegate::OnProcessMessage(CFWL_Message* pMessage) {
1360   if (m_pOwner->m_pWidgetMgr->IsFormDisabled()) {
1361     return DisForm_OnProcessMessage(pMessage);
1362   }
1363   if (!pMessage)
1364     return 0;
1365   FX_DWORD dwMsgCode = pMessage->GetClassID();
1366   FX_BOOL iRet = 1;
1367   switch (dwMsgCode) {
1368     case FWL_MSGHASH_SetFocus:
1369     case FWL_MSGHASH_KillFocus: {
1370       OnFocusChanged(pMessage, dwMsgCode == FWL_MSGHASH_SetFocus);
1371       break;
1372     }
1373     case FWL_MSGHASH_Mouse: {
1374       CFWL_MsgMouse* pMsg = static_cast<CFWL_MsgMouse*>(pMessage);
1375       FX_DWORD dwCmd = pMsg->m_dwCmd;
1376       switch (dwCmd) {
1377         case FWL_MSGMOUSECMD_LButtonDown: {
1378           OnLButtonDown(pMsg);
1379           break;
1380         }
1381         case FWL_MSGMOUSECMD_LButtonUp: {
1382           OnLButtonUp(pMsg);
1383           break;
1384         }
1385         case FWL_MSGMOUSECMD_MouseMove: {
1386           OnMouseMove(pMsg);
1387           break;
1388         }
1389         case FWL_MSGMOUSECMD_MouseLeave: {
1390           OnMouseLeave(pMsg);
1391           break;
1392         }
1393         default: {}
1394       }
1395       break;
1396     }
1397     case FWL_MSGHASH_Key: {
1398       OnKey(static_cast<CFWL_MsgKey*>(pMessage));
1399       break;
1400     }
1401     default: { iRet = 0; }
1402   }
1403   CFWL_WidgetImpDelegate::OnProcessMessage(pMessage);
1404   return iRet;
1405 }
OnProcessEvent(CFWL_Event * pEvent)1406 FWL_ERR CFWL_ComboBoxImpDelegate::OnProcessEvent(CFWL_Event* pEvent) {
1407   FX_DWORD dwFlag = pEvent->GetClassID();
1408   if (dwFlag == FWL_EVTHASH_LTB_DrawItem) {
1409     CFWL_EvtLtbDrawItem* pDrawItemEvent =
1410         static_cast<CFWL_EvtLtbDrawItem*>(pEvent);
1411     CFWL_EvtCmbDrawItem pTemp;
1412     pTemp.m_pSrcTarget = m_pOwner->m_pInterface;
1413     pTemp.m_pGraphics = pDrawItemEvent->m_pGraphics;
1414     pTemp.m_index = pDrawItemEvent->m_index;
1415     pTemp.m_rtItem = pDrawItemEvent->m_rect;
1416     m_pOwner->DispatchEvent(&pTemp);
1417   } else if (dwFlag == FWL_EVTHASH_Scroll) {
1418     CFWL_EvtScroll* pScrollEvent = static_cast<CFWL_EvtScroll*>(pEvent);
1419     CFWL_EvtScroll pScrollEv;
1420     pScrollEv.m_pSrcTarget = m_pOwner->m_pInterface;
1421     pScrollEv.m_iScrollCode = pScrollEvent->m_iScrollCode;
1422     pScrollEv.m_fPos = pScrollEvent->m_fPos;
1423     m_pOwner->DispatchEvent(&pScrollEv);
1424   } else if (dwFlag == FWL_EVTHASH_EDT_TextChanged) {
1425     CFWL_EvtEdtTextChanged* pTextChangedEvent =
1426         static_cast<CFWL_EvtEdtTextChanged*>(pEvent);
1427     CFWL_EvtCmbEditChanged pTemp;
1428     pTemp.m_pSrcTarget = m_pOwner->m_pInterface;
1429     pTemp.wsInsert = pTextChangedEvent->wsInsert;
1430     pTemp.wsDelete = pTextChangedEvent->wsDelete;
1431     pTemp.nChangeType = pTextChangedEvent->nChangeType;
1432     m_pOwner->DispatchEvent(&pTemp);
1433   }
1434   return FWL_ERR_Succeeded;
1435 }
OnDrawWidget(CFX_Graphics * pGraphics,const CFX_Matrix * pMatrix)1436 FWL_ERR CFWL_ComboBoxImpDelegate::OnDrawWidget(CFX_Graphics* pGraphics,
1437                                                const CFX_Matrix* pMatrix) {
1438   return m_pOwner->DrawWidget(pGraphics, pMatrix);
1439 }
OnFocusChanged(CFWL_Message * pMsg,FX_BOOL bSet)1440 void CFWL_ComboBoxImpDelegate::OnFocusChanged(CFWL_Message* pMsg,
1441                                               FX_BOOL bSet) {
1442   IFWL_Target* pDstTarget = pMsg->m_pDstTarget;
1443   IFWL_Target* pSrcTarget = pMsg->m_pSrcTarget;
1444   FX_BOOL bDropDown = m_pOwner->IsDropDownStyle();
1445   if (bSet) {
1446     m_pOwner->m_pProperties->m_dwStates |= FWL_WGTSTATE_Focused;
1447     if (bDropDown && pSrcTarget != m_pOwner->m_pListBox.get()) {
1448       if (!m_pOwner->m_pEdit)
1449         return;
1450       static_cast<CFWL_ComboEditImp*>(m_pOwner->m_pEdit->GetImpl())
1451           ->SetSelected();
1452     } else {
1453       m_pOwner->Repaint(&m_pOwner->m_rtClient);
1454     }
1455   } else {
1456     m_pOwner->m_pProperties->m_dwStates &= ~FWL_WGTSTATE_Focused;
1457     if (bDropDown && pDstTarget != m_pOwner->m_pListBox.get()) {
1458       if (!m_pOwner->m_pEdit)
1459         return;
1460       static_cast<CFWL_ComboEditImp*>(m_pOwner->m_pEdit->GetImpl())
1461           ->FlagFocus(FALSE);
1462       static_cast<CFWL_ComboEditImp*>(m_pOwner->m_pEdit->GetImpl())
1463           ->ClearSelected();
1464     } else {
1465       m_pOwner->Repaint(&m_pOwner->m_rtClient);
1466     }
1467   }
1468 }
OnLButtonDown(CFWL_MsgMouse * pMsg)1469 void CFWL_ComboBoxImpDelegate::OnLButtonDown(CFWL_MsgMouse* pMsg) {
1470   if (m_pOwner->m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled) {
1471     return;
1472   }
1473   FX_BOOL bDropDown = m_pOwner->IsDropDownStyle();
1474   CFX_RectF& rtBtn = bDropDown ? m_pOwner->m_rtBtn : m_pOwner->m_rtClient;
1475   FX_BOOL bClickBtn = rtBtn.Contains(pMsg->m_fx, pMsg->m_fy);
1476   if (bClickBtn) {
1477     if (bDropDown && m_pOwner->m_pEdit) {
1478       m_pOwner->MatchEditText();
1479     }
1480     m_pOwner->m_bLButtonDown = TRUE;
1481     m_pOwner->m_iBtnState = FWL_PARTSTATE_CMB_Pressed;
1482     m_pOwner->Repaint(&m_pOwner->m_rtClient);
1483     m_pOwner->ShowDropList(TRUE);
1484     m_pOwner->m_iBtnState = FWL_PARTSTATE_CMB_Normal;
1485     m_pOwner->Repaint(&m_pOwner->m_rtClient);
1486   }
1487 }
OnLButtonUp(CFWL_MsgMouse * pMsg)1488 void CFWL_ComboBoxImpDelegate::OnLButtonUp(CFWL_MsgMouse* pMsg) {
1489   m_pOwner->m_bLButtonDown = FALSE;
1490   if (m_pOwner->m_rtBtn.Contains(pMsg->m_fx, pMsg->m_fy)) {
1491     m_pOwner->m_iBtnState = FWL_PARTSTATE_CMB_Hovered;
1492   } else {
1493     m_pOwner->m_iBtnState = FWL_PARTSTATE_CMB_Normal;
1494   }
1495   m_pOwner->Repaint(&m_pOwner->m_rtBtn);
1496 }
OnMouseMove(CFWL_MsgMouse * pMsg)1497 void CFWL_ComboBoxImpDelegate::OnMouseMove(CFWL_MsgMouse* pMsg) {
1498   int32_t iOldState = m_pOwner->m_iBtnState;
1499   if (m_pOwner->m_rtBtn.Contains(pMsg->m_fx, pMsg->m_fy)) {
1500     m_pOwner->m_iBtnState = m_pOwner->m_bLButtonDown
1501                                 ? FWL_PARTSTATE_CMB_Pressed
1502                                 : FWL_PARTSTATE_CMB_Hovered;
1503   } else {
1504     m_pOwner->m_iBtnState = FWL_PARTSTATE_CMB_Normal;
1505   }
1506   if ((iOldState != m_pOwner->m_iBtnState) &&
1507       !((m_pOwner->m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled) ==
1508         FWL_WGTSTATE_Disabled)) {
1509     m_pOwner->Repaint(&m_pOwner->m_rtBtn);
1510   }
1511 }
OnMouseLeave(CFWL_MsgMouse * pMsg)1512 void CFWL_ComboBoxImpDelegate::OnMouseLeave(CFWL_MsgMouse* pMsg) {
1513   if (!m_pOwner->IsDropListShowed() &&
1514       !((m_pOwner->m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled) ==
1515         FWL_WGTSTATE_Disabled)) {
1516     m_pOwner->m_iBtnState = FWL_PARTSTATE_CMB_Normal;
1517     m_pOwner->Repaint(&m_pOwner->m_rtBtn);
1518   }
1519 }
OnKey(CFWL_MsgKey * pMsg)1520 void CFWL_ComboBoxImpDelegate::OnKey(CFWL_MsgKey* pMsg) {
1521   FX_DWORD dwKeyCode = pMsg->m_dwKeyCode;
1522   if (dwKeyCode == FWL_VKEY_Tab) {
1523     m_pOwner->DispatchKeyEvent(pMsg);
1524     return;
1525   }
1526   FX_BOOL bSubCtrlKey = pMsg->m_pDstTarget == m_pOwner->m_pInterface;
1527   if (bSubCtrlKey) {
1528     DoSubCtrlKey(pMsg);
1529   }
1530 }
DoSubCtrlKey(CFWL_MsgKey * pMsg)1531 void CFWL_ComboBoxImpDelegate::DoSubCtrlKey(CFWL_MsgKey* pMsg) {
1532   FX_DWORD dwKeyCode = pMsg->m_dwKeyCode;
1533   FX_BOOL bUp = dwKeyCode == FWL_VKEY_Up;
1534   FX_BOOL bDown = dwKeyCode == FWL_VKEY_Down;
1535   if (bUp || bDown) {
1536     int32_t iCount = static_cast<CFWL_ComboListImp*>(
1537                          m_pOwner->m_pListBox->GetImpl())->CountItems();
1538     if (iCount < 1) {
1539       return;
1540     }
1541     FX_BOOL bMatchEqual = FALSE;
1542     int32_t iCurSel = m_pOwner->m_iCurSel;
1543     FX_BOOL bDropDown = m_pOwner->IsDropDownStyle();
1544     if (bDropDown && m_pOwner->m_pEdit) {
1545       CFX_WideString wsText;
1546       m_pOwner->m_pEdit->GetText(wsText);
1547       iCurSel = static_cast<CFWL_ComboListImp*>(m_pOwner->m_pListBox->GetImpl())
1548                     ->MatchItem(wsText);
1549       if (iCurSel >= 0) {
1550         CFX_WideString wsTemp;
1551         IFWL_ComboBoxDP* pData = static_cast<IFWL_ComboBoxDP*>(
1552             m_pOwner->m_pProperties->m_pDataProvider);
1553         FWL_HLISTITEM hItem = pData->GetItem(m_pOwner->m_pInterface, iCurSel);
1554         static_cast<CFWL_ComboListImp*>(m_pOwner->m_pListBox->GetImpl())
1555             ->GetItemText(hItem, wsTemp);
1556         bMatchEqual = wsText.Equal(wsTemp);
1557       }
1558     }
1559     if (iCurSel < 0) {
1560       iCurSel = 0;
1561     } else if (!bDropDown || bMatchEqual) {
1562       if ((bUp && iCurSel == 0) || (bDown && iCurSel == iCount - 1)) {
1563         return;
1564       }
1565       if (bUp) {
1566         iCurSel--;
1567       } else {
1568         iCurSel++;
1569       }
1570     }
1571     m_pOwner->m_iCurSel = iCurSel;
1572     if (bDropDown && m_pOwner->m_pEdit) {
1573       m_pOwner->SynchrEditText(m_pOwner->m_iCurSel);
1574     } else {
1575       m_pOwner->Repaint(&m_pOwner->m_rtClient);
1576     }
1577     return;
1578   }
1579   FX_BOOL bDropDown = m_pOwner->IsDropDownStyle();
1580   if (bDropDown) {
1581     IFWL_WidgetDelegate* pDelegate = m_pOwner->m_pEdit->SetDelegate(NULL);
1582     pDelegate->OnProcessMessage(pMsg);
1583   }
1584 }
DisForm_OnProcessMessage(CFWL_Message * pMessage)1585 int32_t CFWL_ComboBoxImpDelegate::DisForm_OnProcessMessage(
1586     CFWL_Message* pMessage) {
1587   if (!pMessage)
1588     return 0;
1589   FX_DWORD dwMsgCode = pMessage->GetClassID();
1590   FX_BOOL backDefault = TRUE;
1591   switch (dwMsgCode) {
1592     case FWL_MSGHASH_SetFocus:
1593     case FWL_MSGHASH_KillFocus: {
1594       backDefault = FALSE;
1595       DisForm_OnFocusChanged(pMessage, dwMsgCode == FWL_MSGHASH_SetFocus);
1596       break;
1597     }
1598     case FWL_MSGHASH_Mouse: {
1599       backDefault = FALSE;
1600       CFWL_MsgMouse* pMsg = static_cast<CFWL_MsgMouse*>(pMessage);
1601       FX_DWORD dwCmd = pMsg->m_dwCmd;
1602       switch (dwCmd) {
1603         case FWL_MSGMOUSECMD_LButtonDown: {
1604           DisForm_OnLButtonDown(pMsg);
1605           break;
1606         }
1607         case FWL_MSGMOUSECMD_LButtonUp: {
1608           OnLButtonUp(pMsg);
1609           break;
1610         }
1611         default: {}
1612       }
1613       break;
1614     }
1615     case FWL_MSGHASH_Key: {
1616       backDefault = FALSE;
1617       CFWL_MsgKey* pKey = static_cast<CFWL_MsgKey*>(pMessage);
1618       if (pKey->m_dwCmd == FWL_MSGKEYCMD_KeyUp) {
1619         break;
1620       }
1621       if (m_pOwner->DisForm_IsDropListShowed() &&
1622           pKey->m_dwCmd == FWL_MSGKEYCMD_KeyDown) {
1623         FX_DWORD dwKeyCode = pKey->m_dwKeyCode;
1624         FX_BOOL bListKey =
1625             dwKeyCode == FWL_VKEY_Up || dwKeyCode == FWL_VKEY_Down ||
1626             dwKeyCode == FWL_VKEY_Return || dwKeyCode == FWL_VKEY_Escape;
1627         if (bListKey) {
1628           IFWL_WidgetDelegate* pDelegate =
1629               m_pOwner->m_pListBox->SetDelegate(NULL);
1630           pDelegate->OnProcessMessage(pMessage);
1631           break;
1632         }
1633       }
1634       DisForm_OnKey(pKey);
1635       break;
1636     }
1637     default: {}
1638   }
1639   if (!backDefault) {
1640     return 1;
1641   }
1642   return CFWL_WidgetImpDelegate::OnProcessMessage(pMessage);
1643 }
DisForm_OnLButtonDown(CFWL_MsgMouse * pMsg)1644 void CFWL_ComboBoxImpDelegate::DisForm_OnLButtonDown(CFWL_MsgMouse* pMsg) {
1645   FX_BOOL bDropDown = m_pOwner->DisForm_IsDropListShowed();
1646   CFX_RectF& rtBtn = bDropDown ? m_pOwner->m_rtBtn : m_pOwner->m_rtClient;
1647   FX_BOOL bClickBtn = rtBtn.Contains(pMsg->m_fx, pMsg->m_fy);
1648   if (bClickBtn) {
1649     if (m_pOwner->DisForm_IsDropListShowed()) {
1650       m_pOwner->DisForm_ShowDropList(FALSE);
1651       return;
1652     }
1653     {
1654       if (m_pOwner->m_pEdit) {
1655         m_pOwner->MatchEditText();
1656       }
1657       m_pOwner->DisForm_ShowDropList(TRUE);
1658     }
1659   }
1660 }
DisForm_OnFocusChanged(CFWL_Message * pMsg,FX_BOOL bSet)1661 void CFWL_ComboBoxImpDelegate::DisForm_OnFocusChanged(CFWL_Message* pMsg,
1662                                                       FX_BOOL bSet) {
1663   if (bSet) {
1664     m_pOwner->m_pProperties->m_dwStates |= FWL_WGTSTATE_Focused;
1665     if ((m_pOwner->m_pEdit->GetStates() & FWL_WGTSTATE_Focused) == 0) {
1666       CFWL_MsgSetFocus msg;
1667       msg.m_pDstTarget = m_pOwner->m_pEdit.get();
1668       msg.m_pSrcTarget = NULL;
1669       IFWL_WidgetDelegate* pDelegate = m_pOwner->m_pEdit->SetDelegate(NULL);
1670       pDelegate->OnProcessMessage(&msg);
1671     }
1672   } else {
1673     m_pOwner->m_pProperties->m_dwStates &= ~FWL_WGTSTATE_Focused;
1674     m_pOwner->DisForm_ShowDropList(FALSE);
1675     CFWL_MsgKillFocus msg;
1676     msg.m_pDstTarget = NULL;
1677     msg.m_pSrcTarget = m_pOwner->m_pEdit.get();
1678     IFWL_WidgetDelegate* pDelegate = m_pOwner->m_pEdit->SetDelegate(NULL);
1679     pDelegate->OnProcessMessage(&msg);
1680   }
1681 }
DisForm_OnKey(CFWL_MsgKey * pMsg)1682 void CFWL_ComboBoxImpDelegate::DisForm_OnKey(CFWL_MsgKey* pMsg) {
1683   FX_DWORD dwKeyCode = pMsg->m_dwKeyCode;
1684   FX_BOOL bUp = dwKeyCode == FWL_VKEY_Up;
1685   FX_BOOL bDown = dwKeyCode == FWL_VKEY_Down;
1686   if (bUp || bDown) {
1687     CFWL_ComboListImp* pComboList =
1688         static_cast<CFWL_ComboListImp*>(m_pOwner->m_pListBox->GetImpl());
1689     int32_t iCount = pComboList->CountItems();
1690     if (iCount < 1) {
1691       return;
1692     }
1693     FX_BOOL bMatchEqual = FALSE;
1694     int32_t iCurSel = m_pOwner->m_iCurSel;
1695     if (m_pOwner->m_pEdit) {
1696       CFX_WideString wsText;
1697       m_pOwner->m_pEdit->GetText(wsText);
1698       iCurSel = pComboList->MatchItem(wsText);
1699       if (iCurSel >= 0) {
1700         CFX_WideString wsTemp;
1701         FWL_HLISTITEM item = m_pOwner->m_pListBox->GetSelItem(iCurSel);
1702         m_pOwner->m_pListBox->GetItemText(item, wsTemp);
1703         bMatchEqual = wsText.Equal(wsTemp);
1704       }
1705     }
1706     if (iCurSel < 0) {
1707       iCurSel = 0;
1708     } else if (bMatchEqual) {
1709       if ((bUp && iCurSel == 0) || (bDown && iCurSel == iCount - 1)) {
1710         return;
1711       }
1712       if (bUp) {
1713         iCurSel--;
1714       } else {
1715         iCurSel++;
1716       }
1717     }
1718     m_pOwner->m_iCurSel = iCurSel;
1719     m_pOwner->SynchrEditText(m_pOwner->m_iCurSel);
1720     return;
1721   }
1722   if (m_pOwner->m_pEdit) {
1723     IFWL_WidgetDelegate* pDelegate = m_pOwner->m_pEdit->SetDelegate(NULL);
1724     pDelegate->OnProcessMessage(pMsg);
1725   }
1726 }
CFWL_ComboProxyImpDelegate(IFWL_Form * pForm,CFWL_ComboBoxImp * pComboBox)1727 CFWL_ComboProxyImpDelegate::CFWL_ComboProxyImpDelegate(
1728     IFWL_Form* pForm,
1729     CFWL_ComboBoxImp* pComboBox)
1730     : m_bLButtonDown(FALSE),
1731       m_bLButtonUpSelf(FALSE),
1732       m_fStartPos(0),
1733       m_pForm(pForm),
1734       m_pComboBox(pComboBox) {
1735 }
OnProcessMessage(CFWL_Message * pMessage)1736 int32_t CFWL_ComboProxyImpDelegate::OnProcessMessage(CFWL_Message* pMessage) {
1737   if (!pMessage)
1738     return 0;
1739   FX_DWORD dwMsgCode = pMessage->GetClassID();
1740   if (dwMsgCode == FWL_MSGHASH_Mouse) {
1741     CFWL_MsgMouse* pMsg = static_cast<CFWL_MsgMouse*>(pMessage);
1742     FX_DWORD dwCmd = pMsg->m_dwCmd;
1743     switch (dwCmd) {
1744       case FWL_MSGMOUSECMD_LButtonDown: {
1745         OnLButtonDown(pMsg);
1746         break;
1747       }
1748       case FWL_MSGMOUSECMD_LButtonUp: {
1749         OnLButtonUp(pMsg);
1750         break;
1751       }
1752       case FWL_MSGMOUSECMD_MouseMove: {
1753         OnMouseMove(pMsg);
1754         break;
1755       }
1756       default: {}
1757     }
1758   }
1759   if (dwMsgCode == FWL_MSGHASH_Deactivate) {
1760     OnDeactive(static_cast<CFWL_MsgDeactivate*>(pMessage));
1761   }
1762   if (dwMsgCode == FWL_MSGHASH_KillFocus || dwMsgCode == FWL_MSGHASH_SetFocus) {
1763     OnFocusChanged(static_cast<CFWL_MsgKillFocus*>(pMessage),
1764                    dwMsgCode == FWL_MSGHASH_SetFocus);
1765   }
1766   return CFWL_WidgetImpDelegate::OnProcessMessage(pMessage);
1767 }
OnDrawWidget(CFX_Graphics * pGraphics,const CFX_Matrix * pMatrix)1768 FWL_ERR CFWL_ComboProxyImpDelegate::OnDrawWidget(CFX_Graphics* pGraphics,
1769                                                  const CFX_Matrix* pMatrix) {
1770   m_pComboBox->DrawStretchHandler(pGraphics, pMatrix);
1771   return FWL_ERR_Succeeded;
1772 }
OnLButtonDown(CFWL_MsgMouse * pMsg)1773 void CFWL_ComboProxyImpDelegate::OnLButtonDown(CFWL_MsgMouse* pMsg) {
1774   IFWL_NoteThread* pThread = m_pForm->GetOwnerThread();
1775   if (!pThread)
1776     return;
1777   CFWL_NoteDriver* pDriver =
1778       static_cast<CFWL_NoteDriver*>(pThread->GetNoteDriver());
1779   CFX_RectF rtWidget;
1780   m_pForm->GetWidgetRect(rtWidget);
1781   rtWidget.left = rtWidget.top = 0;
1782   if (rtWidget.Contains(pMsg->m_fx, pMsg->m_fy)) {
1783     m_bLButtonDown = TRUE;
1784     pDriver->SetGrab(m_pForm, TRUE);
1785   } else {
1786     m_bLButtonDown = FALSE;
1787     pDriver->SetGrab(m_pForm, FALSE);
1788     m_pComboBox->ShowDropList(FALSE);
1789     return;
1790   }
1791   IFWL_AdapterNative* pNative = FWL_GetAdapterNative();
1792   IFWL_AdapterCursorMgr* pCursorMgr = pNative->GetCursorMgr();
1793   FWL_HCURSOR hCursor = pCursorMgr->GetSystemCursor(FWL_CURSORTYPE_SizeNS);
1794   pCursorMgr->SetCursor(hCursor);
1795   pCursorMgr->ShowCursor(TRUE);
1796   m_pForm->TransformTo(NULL, pMsg->m_fx, pMsg->m_fy);
1797   m_fStartPos = pMsg->m_fy;
1798 }
OnLButtonUp(CFWL_MsgMouse * pMsg)1799 void CFWL_ComboProxyImpDelegate::OnLButtonUp(CFWL_MsgMouse* pMsg) {
1800   m_bLButtonDown = FALSE;
1801   IFWL_NoteThread* pThread = m_pForm->GetOwnerThread();
1802   if (!pThread)
1803     return;
1804   CFWL_NoteDriver* pDriver =
1805       static_cast<CFWL_NoteDriver*>(pThread->GetNoteDriver());
1806   pDriver->SetGrab(m_pForm, FALSE);
1807   if (m_bLButtonUpSelf) {
1808     CFX_RectF rect;
1809     m_pForm->GetWidgetRect(rect);
1810     rect.left = rect.top = 0;
1811     if (!rect.Contains(pMsg->m_fx, pMsg->m_fy) &&
1812         m_pComboBox->IsDropListShowed()) {
1813       m_pComboBox->ShowDropList(FALSE);
1814     }
1815   } else {
1816     m_bLButtonUpSelf = TRUE;
1817   }
1818 }
OnMouseMove(CFWL_MsgMouse * pMsg)1819 void CFWL_ComboProxyImpDelegate::OnMouseMove(CFWL_MsgMouse* pMsg) {
1820   IFWL_AdapterNative* pNative = FWL_GetAdapterNative();
1821   IFWL_AdapterCursorMgr* pCursorMgr = pNative->GetCursorMgr();
1822   FWL_CURSORTYPE cursorType = FWL_CURSORTYPE_Arrow;
1823   if (m_pComboBox->m_rtHandler.Contains(pMsg->m_fx, pMsg->m_fy)) {
1824     cursorType = FWL_CURSORTYPE_SizeNS;
1825   }
1826   FWL_HCURSOR hCursor = pCursorMgr->GetSystemCursor(cursorType);
1827   pCursorMgr->SetCursor(hCursor);
1828   pCursorMgr->ShowCursor(TRUE);
1829   if (!m_bLButtonDown) {
1830     return;
1831   }
1832   m_pForm->TransformTo(NULL, pMsg->m_fx, pMsg->m_fy);
1833   FX_FLOAT fChanged = pMsg->m_fy - m_fStartPos;
1834   if (m_pComboBox->m_bUpFormHandler) {
1835     fChanged = m_fStartPos - pMsg->m_fy;
1836   }
1837   if (m_pComboBox->m_rtList.height + fChanged < m_pComboBox->m_fItemHeight) {
1838     return;
1839   }
1840   m_pComboBox->m_rtList.height += fChanged;
1841   m_pComboBox->m_rtProxy.height += fChanged;
1842   if (m_pComboBox->m_bUpFormHandler) {
1843     m_pComboBox->m_rtProxy.top -= fChanged;
1844     m_pComboBox->m_rtHandler.Set(0, 0, m_pComboBox->m_rtList.width,
1845                                  m_pComboBox->m_fComboFormHandler);
1846   } else {
1847     m_pComboBox->m_rtHandler.Set(0, m_pComboBox->m_rtList.height,
1848                                  m_pComboBox->m_rtList.width,
1849                                  m_pComboBox->m_fComboFormHandler);
1850   }
1851   m_pForm->SetWidgetRect(m_pComboBox->m_rtProxy);
1852   m_pComboBox->m_pListBox->SetWidgetRect(m_pComboBox->m_rtList);
1853   m_pComboBox->m_pListBox->Update();
1854   m_fStartPos = pMsg->m_fy;
1855 }
OnDeactive(CFWL_MsgDeactivate * pMsg)1856 void CFWL_ComboProxyImpDelegate::OnDeactive(CFWL_MsgDeactivate* pMsg) {
1857   m_pComboBox->ShowDropList(FALSE);
1858 }
OnFocusChanged(CFWL_MsgKillFocus * pMsg,FX_BOOL bSet)1859 void CFWL_ComboProxyImpDelegate::OnFocusChanged(CFWL_MsgKillFocus* pMsg,
1860                                                 FX_BOOL bSet) {
1861   if (!bSet) {
1862     if (pMsg->m_pSetFocus == NULL) {
1863       m_pComboBox->ShowDropList(FALSE);
1864     }
1865   }
1866 }
1867