blob: cbfbd9a447d6a468b5963a40461905cfc9404484 [file] [log] [blame]
Tom Sepez99ffdb02016-01-26 14:51:21 -08001// 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
dsinclair447b1f32016-12-08 10:06:32 -08007#include "xfa/fwl/cfwl_combobox.h"
Dan Sinclaire73c5ce2016-02-25 13:38:37 -05008
dsinclair2c489cc2016-11-23 16:17:20 -08009#include <algorithm>
10#include <memory>
Tom Sepeze059b5b2016-02-05 11:49:27 -080011#include <utility>
Tom Sepez99ffdb02016-01-26 14:51:21 -080012
dsinclair6fe87952016-11-01 18:48:19 -070013#include "third_party/base/ptr_util.h"
Dan Sinclair68eefa62017-08-30 12:16:16 -040014#include "xfa/fde/cfde_texteditengine.h"
Dan Sinclairbccf5732017-03-30 14:10:32 -040015#include "xfa/fde/cfde_textout.h"
dsinclair447b1f32016-12-08 10:06:32 -080016#include "xfa/fwl/cfwl_app.h"
17#include "xfa/fwl/cfwl_event.h"
18#include "xfa/fwl/cfwl_eventselectchanged.h"
19#include "xfa/fwl/cfwl_eventtextchanged.h"
20#include "xfa/fwl/cfwl_formproxy.h"
21#include "xfa/fwl/cfwl_listbox.h"
22#include "xfa/fwl/cfwl_messagekey.h"
23#include "xfa/fwl/cfwl_messagekillfocus.h"
24#include "xfa/fwl/cfwl_messagemouse.h"
25#include "xfa/fwl/cfwl_messagesetfocus.h"
26#include "xfa/fwl/cfwl_notedriver.h"
27#include "xfa/fwl/cfwl_themebackground.h"
28#include "xfa/fwl/cfwl_themepart.h"
29#include "xfa/fwl/cfwl_themetext.h"
30#include "xfa/fwl/cfwl_widgetmgr.h"
31#include "xfa/fwl/ifwl_themeprovider.h"
Tom Sepez99ffdb02016-01-26 14:51:21 -080032
dsinclair2c489cc2016-11-23 16:17:20 -080033CFWL_ComboBox::CFWL_ComboBox(const CFWL_App* app)
34 : CFWL_Widget(app, pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr),
35 m_pComboBoxProxy(nullptr),
36 m_bLButtonDown(false),
37 m_iCurSel(-1),
Dan Sinclairc635c932017-01-03 15:46:55 -050038 m_iBtnState(CFWL_PartState_Normal) {
dsinclair2c489cc2016-11-23 16:17:20 -080039 m_rtClient.Reset();
40 m_rtBtn.Reset();
41 m_rtHandler.Reset();
dsinclair42cb6452016-10-31 12:50:04 -070042
dsinclair2c489cc2016-11-23 16:17:20 -080043 if (m_pWidgetMgr->IsFormDisabled()) {
44 DisForm_InitComboList();
45 DisForm_InitComboEdit();
46 return;
47 }
48
49 auto prop = pdfium::MakeUnique<CFWL_WidgetProperties>();
50 prop->m_pThemeProvider = m_pProperties->m_pThemeProvider;
51 prop->m_dwStyles |= FWL_WGTSTYLE_Border | FWL_WGTSTYLE_VScroll;
Tom Sepez797ca5c2017-05-25 12:03:18 -070052 m_pListBox = pdfium::MakeUnique<CFWL_ComboList>(m_pOwnerApp.Get(),
53 std::move(prop), this);
dsinclair2c489cc2016-11-23 16:17:20 -080054
55 if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_CMB_DropDown) && !m_pEdit) {
tsepeza9caab92016-12-14 05:57:10 -080056 m_pEdit = pdfium::MakeUnique<CFWL_ComboEdit>(
Tom Sepez797ca5c2017-05-25 12:03:18 -070057 m_pOwnerApp.Get(), pdfium::MakeUnique<CFWL_WidgetProperties>(), this);
dsinclair2c489cc2016-11-23 16:17:20 -080058 m_pEdit->SetOuter(this);
59 }
60 if (m_pEdit)
61 m_pEdit->SetParent(this);
62
63 SetStates(m_pProperties->m_dwStates);
dsinclair42cb6452016-10-31 12:50:04 -070064}
65
dsinclair20855382016-10-31 07:29:34 -070066CFWL_ComboBox::~CFWL_ComboBox() {}
67
dsinclair2c489cc2016-11-23 16:17:20 -080068FWL_Type CFWL_ComboBox::GetClassID() const {
69 return FWL_Type::ComboBox;
70}
dsinclair20855382016-10-31 07:29:34 -070071
Dan Sinclair0ced8272016-11-23 12:20:47 -050072void CFWL_ComboBox::AddString(const CFX_WideStringC& wsText) {
dsinclair2c489cc2016-11-23 16:17:20 -080073 m_pListBox->AddString(wsText);
Tom Sepez99ffdb02016-01-26 14:51:21 -080074}
dsinclair7f432a12016-03-29 12:38:01 -070075
dsinclair603f57b2016-12-14 06:25:02 -080076void CFWL_ComboBox::RemoveAt(int32_t iIndex) {
77 m_pListBox->RemoveAt(iIndex);
Tom Sepez99ffdb02016-01-26 14:51:21 -080078}
dsinclair7f432a12016-03-29 12:38:01 -070079
Tom Sepeze059b5b2016-02-05 11:49:27 -080080void CFWL_ComboBox::RemoveAll() {
dsinclair2c489cc2016-11-23 16:17:20 -080081 m_pListBox->DeleteAll();
82}
83
84void CFWL_ComboBox::ModifyStylesEx(uint32_t dwStylesExAdded,
85 uint32_t dwStylesExRemoved) {
86 if (m_pWidgetMgr->IsFormDisabled()) {
87 DisForm_ModifyStylesEx(dwStylesExAdded, dwStylesExRemoved);
88 return;
89 }
90
91 bool bAddDropDown = !!(dwStylesExAdded & FWL_STYLEEXT_CMB_DropDown);
92 bool bRemoveDropDown = !!(dwStylesExRemoved & FWL_STYLEEXT_CMB_DropDown);
93 if (bAddDropDown && !m_pEdit) {
94 m_pEdit = pdfium::MakeUnique<CFWL_ComboEdit>(
Tom Sepez797ca5c2017-05-25 12:03:18 -070095 m_pOwnerApp.Get(), pdfium::MakeUnique<CFWL_WidgetProperties>(),
96 nullptr);
dsinclair2c489cc2016-11-23 16:17:20 -080097 m_pEdit->SetOuter(this);
98 m_pEdit->SetParent(this);
99 } else if (bRemoveDropDown && m_pEdit) {
dsinclair7fa190d2016-12-07 17:23:28 -0800100 m_pEdit->SetStates(FWL_WGTSTATE_Invisible);
dsinclair2c489cc2016-11-23 16:17:20 -0800101 }
102 CFWL_Widget::ModifyStylesEx(dwStylesExAdded, dwStylesExRemoved);
103}
104
105void CFWL_ComboBox::Update() {
106 if (m_pWidgetMgr->IsFormDisabled()) {
107 DisForm_Update();
108 return;
109 }
110 if (IsLocked())
111 return;
112
113 ResetTheme();
114 if (IsDropDownStyle() && m_pEdit)
115 ResetEditAlignment();
116 if (!m_pProperties->m_pThemeProvider)
117 m_pProperties->m_pThemeProvider = GetAvailableTheme();
118
119 Layout();
dsinclair2c489cc2016-11-23 16:17:20 -0800120}
121
Dan Sinclairb45ea1f2017-02-21 14:27:59 -0500122FWL_WidgetHit CFWL_ComboBox::HitTest(const CFX_PointF& point) {
dsinclair2c489cc2016-11-23 16:17:20 -0800123 if (m_pWidgetMgr->IsFormDisabled())
Dan Sinclairb45ea1f2017-02-21 14:27:59 -0500124 return DisForm_HitTest(point);
125 return CFWL_Widget::HitTest(point);
dsinclair2c489cc2016-11-23 16:17:20 -0800126}
127
Dan Sinclair2b918c82017-07-13 14:47:10 -0400128void CFWL_ComboBox::DrawWidget(CXFA_Graphics* pGraphics,
Lei Zhang4b472142017-08-17 14:30:08 -0700129 const CFX_Matrix& matrix) {
dsinclair2c489cc2016-11-23 16:17:20 -0800130 if (m_pWidgetMgr->IsFormDisabled()) {
Lei Zhang4b472142017-08-17 14:30:08 -0700131 DisForm_DrawWidget(pGraphics, &matrix);
dsinclair2c489cc2016-11-23 16:17:20 -0800132 return;
133 }
134
135 if (!pGraphics)
136 return;
137 if (!m_pProperties->m_pThemeProvider)
138 return;
139
140 IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
141 if (HasBorder())
Lei Zhang4b472142017-08-17 14:30:08 -0700142 DrawBorder(pGraphics, CFWL_Part::Border, pTheme, matrix);
dsinclair2c489cc2016-11-23 16:17:20 -0800143
144 if (!IsDropDownStyle()) {
145 CFX_RectF rtTextBk(m_rtClient);
146 rtTextBk.width -= m_rtBtn.width;
147
148 CFWL_ThemeBackground param;
149 param.m_pWidget = this;
150 param.m_iPart = CFWL_Part::Background;
151 param.m_pGraphics = pGraphics;
Lei Zhang4b472142017-08-17 14:30:08 -0700152 param.m_matrix.Concat(matrix);
dsinclair2c489cc2016-11-23 16:17:20 -0800153 param.m_rtPart = rtTextBk;
154
dsinclair2c489cc2016-11-23 16:17:20 -0800155 if (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled) {
156 param.m_dwStates = CFWL_PartState_Disabled;
157 } else if ((m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) &&
158 (m_iCurSel >= 0)) {
159 param.m_dwStates = CFWL_PartState_Selected;
160 } else {
161 param.m_dwStates = CFWL_PartState_Normal;
162 }
163 pTheme->DrawBackground(&param);
164
165 if (m_iCurSel >= 0) {
166 if (!m_pListBox)
167 return;
168
dsinclair2c489cc2016-11-23 16:17:20 -0800169 CFWL_ListItem* hItem = m_pListBox->GetItem(this, m_iCurSel);
dsinclair2c489cc2016-11-23 16:17:20 -0800170
171 CFWL_ThemeText theme_text;
172 theme_text.m_pWidget = this;
173 theme_text.m_iPart = CFWL_Part::Caption;
174 theme_text.m_dwStates = m_iBtnState;
175 theme_text.m_pGraphics = pGraphics;
Lei Zhang4b472142017-08-17 14:30:08 -0700176 theme_text.m_matrix.Concat(matrix);
dsinclair2c489cc2016-11-23 16:17:20 -0800177 theme_text.m_rtPart = rtTextBk;
178 theme_text.m_dwStates = (m_pProperties->m_dwStates & FWL_WGTSTATE_Focused)
179 ? CFWL_PartState_Selected
180 : CFWL_PartState_Normal;
Dan Sinclairb38c5df2017-01-02 13:38:17 -0500181 theme_text.m_wsText = hItem ? hItem->GetText() : L"";
Dan Sinclairdff02ce2017-08-14 10:26:59 -0400182 theme_text.m_dwTTOStyles.single_line_ = true;
183 theme_text.m_iTTOAlign = FDE_TextAlignment::kCenterLeft;
dsinclair2c489cc2016-11-23 16:17:20 -0800184 pTheme->DrawText(&theme_text);
185 }
186 }
187
188 CFWL_ThemeBackground param;
189 param.m_pWidget = this;
190 param.m_iPart = CFWL_Part::DropDownButton;
191 param.m_dwStates = (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled)
192 ? CFWL_PartState_Disabled
193 : m_iBtnState;
194 param.m_pGraphics = pGraphics;
Lei Zhang4b472142017-08-17 14:30:08 -0700195 param.m_matrix.Concat(matrix);
dsinclair2c489cc2016-11-23 16:17:20 -0800196 param.m_rtPart = m_rtBtn;
197 pTheme->DrawBackground(&param);
198}
199
200void CFWL_ComboBox::SetThemeProvider(IFWL_ThemeProvider* pThemeProvider) {
201 if (!pThemeProvider)
202 return;
203
204 m_pProperties->m_pThemeProvider = pThemeProvider;
205 if (m_pListBox)
206 m_pListBox->SetThemeProvider(pThemeProvider);
207 if (m_pEdit)
208 m_pEdit->SetThemeProvider(pThemeProvider);
Dan Sinclair0ced8272016-11-23 12:20:47 -0500209}
210
dsinclaira2cbc572016-12-07 18:10:16 -0800211CFX_WideString CFWL_ComboBox::GetTextByIndex(int32_t iIndex) const {
dsinclair2c489cc2016-11-23 16:17:20 -0800212 CFWL_ListItem* pItem = static_cast<CFWL_ListItem*>(
213 m_pListBox->GetItem(m_pListBox.get(), iIndex));
dsinclair603f57b2016-12-14 06:25:02 -0800214 return pItem ? pItem->GetText() : L"";
Tom Sepez99ffdb02016-01-26 14:51:21 -0800215}
dsinclair7f432a12016-03-29 12:38:01 -0700216
dsinclair27e66752016-11-11 18:09:57 -0800217void CFWL_ComboBox::SetCurSel(int32_t iSel) {
dsinclair2c489cc2016-11-23 16:17:20 -0800218 int32_t iCount = m_pListBox->CountItems(nullptr);
219 bool bClearSel = iSel < 0 || iSel >= iCount;
220 if (IsDropDownStyle() && m_pEdit) {
221 if (bClearSel) {
222 m_pEdit->SetText(CFX_WideString());
223 } else {
dsinclair2c489cc2016-11-23 16:17:20 -0800224 CFWL_ListItem* hItem = m_pListBox->GetItem(this, iSel);
Dan Sinclairb38c5df2017-01-02 13:38:17 -0500225 m_pEdit->SetText(hItem ? hItem->GetText() : L"");
dsinclair2c489cc2016-11-23 16:17:20 -0800226 }
227 m_pEdit->Update();
228 }
229 m_iCurSel = bClearSel ? -1 : iSel;
230}
231
dsinclair7fa190d2016-12-07 17:23:28 -0800232void CFWL_ComboBox::SetStates(uint32_t dwStates) {
dsinclair2c489cc2016-11-23 16:17:20 -0800233 if (IsDropDownStyle() && m_pEdit)
dsinclair7fa190d2016-12-07 17:23:28 -0800234 m_pEdit->SetStates(dwStates);
dsinclair2c489cc2016-11-23 16:17:20 -0800235 if (m_pListBox)
dsinclair7fa190d2016-12-07 17:23:28 -0800236 m_pListBox->SetStates(dwStates);
237 CFWL_Widget::SetStates(dwStates);
238}
239
240void CFWL_ComboBox::RemoveStates(uint32_t dwStates) {
241 if (IsDropDownStyle() && m_pEdit)
242 m_pEdit->RemoveStates(dwStates);
243 if (m_pListBox)
244 m_pListBox->RemoveStates(dwStates);
245 CFWL_Widget::RemoveStates(dwStates);
Tom Sepez99ffdb02016-01-26 14:51:21 -0800246}
dsinclair7f432a12016-03-29 12:38:01 -0700247
dsinclair98329fe2016-11-10 09:40:14 -0800248void CFWL_ComboBox::SetEditText(const CFX_WideString& wsText) {
dsinclair2c489cc2016-11-23 16:17:20 -0800249 if (!m_pEdit)
250 return;
251
252 m_pEdit->SetText(wsText);
253 m_pEdit->Update();
Tom Sepez99ffdb02016-01-26 14:51:21 -0800254}
dsinclair7f432a12016-03-29 12:38:01 -0700255
dsinclair442997c2016-12-07 17:58:41 -0800256CFX_WideString CFWL_ComboBox::GetEditText() const {
257 if (m_pEdit)
258 return m_pEdit->GetText();
dsinclair2c489cc2016-11-23 16:17:20 -0800259 if (!m_pListBox)
dan sinclair0354ccf2016-11-24 10:45:29 -0500260 return L"";
dsinclair2c489cc2016-11-23 16:17:20 -0800261
262 CFWL_ListItem* hItem = m_pListBox->GetItem(this, m_iCurSel);
Dan Sinclairb38c5df2017-01-02 13:38:17 -0500263 return hItem ? hItem->GetText() : L"";
Tom Sepez99ffdb02016-01-26 14:51:21 -0800264}
dsinclair7f432a12016-03-29 12:38:01 -0700265
dsinclair27e66752016-11-11 18:09:57 -0800266void CFWL_ComboBox::OpenDropDownList(bool bActivate) {
dsinclair2c489cc2016-11-23 16:17:20 -0800267 ShowDropList(bActivate);
Tom Sepez99ffdb02016-01-26 14:51:21 -0800268}
dsinclair7f432a12016-03-29 12:38:01 -0700269
dsinclaira2cbc572016-12-07 18:10:16 -0800270CFX_RectF CFWL_ComboBox::GetBBox() const {
271 if (m_pWidgetMgr->IsFormDisabled())
272 return DisForm_GetBBox();
dsinclair7f432a12016-03-29 12:38:01 -0700273
dsinclaira2cbc572016-12-07 18:10:16 -0800274 CFX_RectF rect = m_pProperties->m_rtWidget;
dsinclair2c489cc2016-11-23 16:17:20 -0800275 if (!m_pListBox || !IsDropListVisible())
dsinclaira2cbc572016-12-07 18:10:16 -0800276 return rect;
dsinclair7f432a12016-03-29 12:38:01 -0700277
dsinclairda911bc2016-12-07 18:47:00 -0800278 CFX_RectF rtList = m_pListBox->GetWidgetRect();
dsinclair2c489cc2016-11-23 16:17:20 -0800279 rtList.Offset(rect.left, rect.top);
280 rect.Union(rtList);
dsinclaira2cbc572016-12-07 18:10:16 -0800281 return rect;
Tom Sepez99ffdb02016-01-26 14:51:21 -0800282}
dsinclair7f432a12016-03-29 12:38:01 -0700283
dsinclair98329fe2016-11-10 09:40:14 -0800284void CFWL_ComboBox::EditModifyStylesEx(uint32_t dwStylesExAdded,
285 uint32_t dwStylesExRemoved) {
dsinclair2c489cc2016-11-23 16:17:20 -0800286 if (m_pEdit)
287 m_pEdit->ModifyStylesEx(dwStylesExAdded, dwStylesExRemoved);
288}
289
Dan Sinclair2b918c82017-07-13 14:47:10 -0400290void CFWL_ComboBox::DrawStretchHandler(CXFA_Graphics* pGraphics,
dsinclair2c489cc2016-11-23 16:17:20 -0800291 const CFX_Matrix* pMatrix) {
292 CFWL_ThemeBackground param;
293 param.m_pGraphics = pGraphics;
294 param.m_iPart = CFWL_Part::StretchHandler;
295 param.m_dwStates = CFWL_PartState_Normal;
296 param.m_pWidget = this;
297 if (pMatrix)
298 param.m_matrix.Concat(*pMatrix);
299 param.m_rtPart = m_rtHandler;
300 m_pProperties->m_pThemeProvider->DrawBackground(&param);
301}
302
303void CFWL_ComboBox::ShowDropList(bool bActivate) {
304 if (m_pWidgetMgr->IsFormDisabled())
305 return DisForm_ShowDropList(bActivate);
306 if (IsDropListVisible() == bActivate)
307 return;
308 if (!m_pComboBoxProxy)
309 InitProxyForm();
310
311 m_pComboBoxProxy->Reset();
312 if (!bActivate) {
313 m_pComboBoxProxy->EndDoModal();
314
315 m_bLButtonDown = false;
316 m_pListBox->SetNotifyOwner(true);
317 SetFocus(true);
318 return;
dsinclair98329fe2016-11-10 09:40:14 -0800319 }
dsinclair2c489cc2016-11-23 16:17:20 -0800320
321 m_pListBox->ChangeSelected(m_iCurSel);
322 ResetListItemAlignment();
323
324 uint32_t dwStyleAdd = m_pProperties->m_dwStyleExes &
325 (FWL_STYLEEXT_CMB_Sort | FWL_STYLEEXT_CMB_OwnerDraw);
326 m_pListBox->ModifyStylesEx(dwStyleAdd, 0);
dsinclairda911bc2016-12-07 18:47:00 -0800327 m_rtList = m_pListBox->GetAutosizedWidgetRect();
dsinclair2c489cc2016-11-23 16:17:20 -0800328
Dan Sinclairbba2a7c2017-02-07 16:36:39 -0500329 CFX_RectF rtAnchor(0, 0, m_pProperties->m_rtWidget.width,
330 m_pProperties->m_rtWidget.height);
dsinclair2c489cc2016-11-23 16:17:20 -0800331
332 m_rtList.width = std::max(m_rtList.width, m_rtClient.width);
333 m_rtProxy = m_rtList;
dsinclair2c489cc2016-11-23 16:17:20 -0800334
335 GetPopupPos(0, m_rtProxy.height, rtAnchor, m_rtProxy);
dsinclair2c489cc2016-11-23 16:17:20 -0800336
dsinclair2c489cc2016-11-23 16:17:20 -0800337 m_pComboBoxProxy->SetWidgetRect(m_rtProxy);
338 m_pComboBoxProxy->Update();
339 m_pListBox->SetWidgetRect(m_rtList);
340 m_pListBox->Update();
341
dsinclair4614b452016-12-07 17:01:58 -0800342 CFWL_Event ev(CFWL_Event::Type::PreDropDown, this);
dsinclair2c489cc2016-11-23 16:17:20 -0800343 DispatchEvent(&ev);
344
dsinclair2c489cc2016-11-23 16:17:20 -0800345 m_pListBox->SetFocus(true);
346 m_pComboBoxProxy->DoModal();
347 m_pListBox->SetFocus(false);
348}
349
350void CFWL_ComboBox::MatchEditText() {
dan sinclair0354ccf2016-11-24 10:45:29 -0500351 CFX_WideString wsText = m_pEdit->GetText();
dsinclair2c489cc2016-11-23 16:17:20 -0800352 int32_t iMatch = m_pListBox->MatchItem(wsText);
353 if (iMatch != m_iCurSel) {
354 m_pListBox->ChangeSelected(iMatch);
355 if (iMatch >= 0)
356 SyncEditText(iMatch);
357 } else if (iMatch >= 0) {
358 m_pEdit->SetSelected();
359 }
360 m_iCurSel = iMatch;
361}
362
363void CFWL_ComboBox::SyncEditText(int32_t iListItem) {
dsinclair2c489cc2016-11-23 16:17:20 -0800364 CFWL_ListItem* hItem = m_pListBox->GetItem(this, iListItem);
Dan Sinclairb38c5df2017-01-02 13:38:17 -0500365 m_pEdit->SetText(hItem ? hItem->GetText() : L"");
dsinclair2c489cc2016-11-23 16:17:20 -0800366 m_pEdit->Update();
367 m_pEdit->SetSelected();
368}
369
370void CFWL_ComboBox::Layout() {
371 if (m_pWidgetMgr->IsFormDisabled())
372 return DisForm_Layout();
373
dsinclair43ac44c2016-12-08 14:05:14 -0800374 m_rtClient = GetClientRect();
Dan Sinclairc635c932017-01-03 15:46:55 -0500375 IFWL_ThemeProvider* theme = GetAvailableTheme();
376 if (!theme)
dsinclair2c489cc2016-11-23 16:17:20 -0800377 return;
378
Dan Sinclair05df0752017-03-14 14:43:42 -0400379 float fBtn = theme->GetScrollBarWidth();
Dan Sinclairbba2a7c2017-02-07 16:36:39 -0500380 m_rtBtn = CFX_RectF(m_rtClient.right() - fBtn, m_rtClient.top, fBtn,
381 m_rtClient.height);
dsinclair2c489cc2016-11-23 16:17:20 -0800382 if (!IsDropDownStyle() || !m_pEdit)
383 return;
384
Dan Sinclairbba2a7c2017-02-07 16:36:39 -0500385 CFX_RectF rtEdit(m_rtClient.left, m_rtClient.top, m_rtClient.width - fBtn,
386 m_rtClient.height);
dsinclair2c489cc2016-11-23 16:17:20 -0800387 m_pEdit->SetWidgetRect(rtEdit);
388
389 if (m_iCurSel >= 0) {
dsinclair2c489cc2016-11-23 16:17:20 -0800390 CFWL_ListItem* hItem = m_pListBox->GetItem(this, m_iCurSel);
dsinclair2c489cc2016-11-23 16:17:20 -0800391 m_pEdit->LockUpdate();
Dan Sinclairb38c5df2017-01-02 13:38:17 -0500392 m_pEdit->SetText(hItem ? hItem->GetText() : L"");
dsinclair2c489cc2016-11-23 16:17:20 -0800393 m_pEdit->UnlockUpdate();
394 }
395 m_pEdit->Update();
396}
397
398void CFWL_ComboBox::ResetTheme() {
399 IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
400 if (!pTheme) {
401 pTheme = GetAvailableTheme();
402 m_pProperties->m_pThemeProvider = pTheme;
403 }
404 if (m_pListBox && !m_pListBox->GetThemeProvider())
405 m_pListBox->SetThemeProvider(pTheme);
406 if (m_pEdit && !m_pEdit->GetThemeProvider())
407 m_pEdit->SetThemeProvider(pTheme);
408}
409
410void CFWL_ComboBox::ResetEditAlignment() {
411 if (!m_pEdit)
412 return;
413
414 uint32_t dwAdd = 0;
415 switch (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_CMB_EditHAlignMask) {
416 case FWL_STYLEEXT_CMB_EditHCenter: {
417 dwAdd |= FWL_STYLEEXT_EDT_HCenter;
418 break;
419 }
dsinclair727a3042016-12-14 13:07:47 -0800420 default: {
421 dwAdd |= FWL_STYLEEXT_EDT_HNear;
dsinclair2c489cc2016-11-23 16:17:20 -0800422 break;
423 }
dsinclair2c489cc2016-11-23 16:17:20 -0800424 }
425 switch (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_CMB_EditVAlignMask) {
426 case FWL_STYLEEXT_CMB_EditVCenter: {
427 dwAdd |= FWL_STYLEEXT_EDT_VCenter;
428 break;
429 }
430 case FWL_STYLEEXT_CMB_EditVFar: {
431 dwAdd |= FWL_STYLEEXT_EDT_VFar;
432 break;
433 }
434 default: {
435 dwAdd |= FWL_STYLEEXT_EDT_VNear;
436 break;
437 }
438 }
439 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_CMB_EditJustified)
440 dwAdd |= FWL_STYLEEXT_EDT_Justified;
dsinclair2c489cc2016-11-23 16:17:20 -0800441
442 m_pEdit->ModifyStylesEx(dwAdd, FWL_STYLEEXT_EDT_HAlignMask |
443 FWL_STYLEEXT_EDT_HAlignModeMask |
444 FWL_STYLEEXT_EDT_VAlignMask);
445}
446
447void CFWL_ComboBox::ResetListItemAlignment() {
448 if (!m_pListBox)
449 return;
450
451 uint32_t dwAdd = 0;
452 switch (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_CMB_ListItemAlignMask) {
453 case FWL_STYLEEXT_CMB_ListItemCenterAlign: {
454 dwAdd |= FWL_STYLEEXT_LTB_CenterAlign;
455 break;
456 }
dsinclair2c489cc2016-11-23 16:17:20 -0800457 default: {
458 dwAdd |= FWL_STYLEEXT_LTB_LeftAlign;
459 break;
460 }
461 }
462 m_pListBox->ModifyStylesEx(dwAdd, FWL_STYLEEXT_CMB_ListItemAlignMask);
463}
464
465void CFWL_ComboBox::ProcessSelChanged(bool bLButtonUp) {
466 m_iCurSel = m_pListBox->GetItemIndex(this, m_pListBox->GetSelItem(0));
467 if (!IsDropDownStyle()) {
dsinclair43ac44c2016-12-08 14:05:14 -0800468 RepaintRect(m_rtClient);
dsinclair2c489cc2016-11-23 16:17:20 -0800469 return;
470 }
471
472 CFWL_ListItem* hItem = m_pListBox->GetItem(this, m_iCurSel);
473 if (!hItem)
474 return;
dsinclair2c489cc2016-11-23 16:17:20 -0800475 if (m_pEdit) {
dsinclair603f57b2016-12-14 06:25:02 -0800476 m_pEdit->SetText(hItem->GetText());
dsinclair2c489cc2016-11-23 16:17:20 -0800477 m_pEdit->Update();
478 m_pEdit->SetSelected();
479 }
480
dsinclair447b1f32016-12-08 10:06:32 -0800481 CFWL_EventSelectChanged ev(this);
dsinclair2c489cc2016-11-23 16:17:20 -0800482 ev.bLButtonUp = bLButtonUp;
dsinclair2c489cc2016-11-23 16:17:20 -0800483 DispatchEvent(&ev);
484}
485
486void CFWL_ComboBox::InitProxyForm() {
487 if (m_pComboBoxProxy)
488 return;
489 if (!m_pListBox)
490 return;
491
492 auto prop = pdfium::MakeUnique<CFWL_WidgetProperties>();
493 prop->m_pOwner = this;
494 prop->m_dwStyles = FWL_WGTSTYLE_Popup;
495 prop->m_dwStates = FWL_WGTSTATE_Invisible;
496
497 // TODO(dsinclair): Does this leak? I don't see a delete, but I'm not sure
498 // if the SetParent call is going to transfer ownership.
Tom Sepez797ca5c2017-05-25 12:03:18 -0700499 m_pComboBoxProxy = new CFWL_ComboBoxProxy(this, m_pOwnerApp.Get(),
500 std::move(prop), m_pListBox.get());
dsinclair2c489cc2016-11-23 16:17:20 -0800501 m_pListBox->SetParent(m_pComboBoxProxy);
502}
503
504void CFWL_ComboBox::DisForm_InitComboList() {
505 if (m_pListBox)
506 return;
507
508 auto prop = pdfium::MakeUnique<CFWL_WidgetProperties>();
509 prop->m_pParent = this;
510 prop->m_dwStyles = FWL_WGTSTYLE_Border | FWL_WGTSTYLE_VScroll;
511 prop->m_dwStates = FWL_WGTSTATE_Invisible;
512 prop->m_pThemeProvider = m_pProperties->m_pThemeProvider;
Tom Sepez797ca5c2017-05-25 12:03:18 -0700513 m_pListBox = pdfium::MakeUnique<CFWL_ComboList>(m_pOwnerApp.Get(),
514 std::move(prop), this);
dsinclair2c489cc2016-11-23 16:17:20 -0800515}
516
517void CFWL_ComboBox::DisForm_InitComboEdit() {
518 if (m_pEdit)
519 return;
520
521 auto prop = pdfium::MakeUnique<CFWL_WidgetProperties>();
522 prop->m_pParent = this;
523 prop->m_pThemeProvider = m_pProperties->m_pThemeProvider;
524
Tom Sepez797ca5c2017-05-25 12:03:18 -0700525 m_pEdit = pdfium::MakeUnique<CFWL_ComboEdit>(m_pOwnerApp.Get(),
526 std::move(prop), this);
dsinclair2c489cc2016-11-23 16:17:20 -0800527 m_pEdit->SetOuter(this);
528}
529
530void CFWL_ComboBox::DisForm_ShowDropList(bool bActivate) {
531 if (DisForm_IsDropListVisible() == bActivate)
532 return;
533
534 if (bActivate) {
dsinclair4614b452016-12-07 17:01:58 -0800535 CFWL_Event preEvent(CFWL_Event::Type::PreDropDown, this);
dsinclair2c489cc2016-11-23 16:17:20 -0800536 DispatchEvent(&preEvent);
537
538 CFWL_ComboList* pComboList = m_pListBox.get();
539 int32_t iItems = pComboList->CountItems(nullptr);
540 if (iItems < 1)
541 return;
542
543 ResetListItemAlignment();
544 pComboList->ChangeSelected(m_iCurSel);
545
Dan Sinclair05df0752017-03-14 14:43:42 -0400546 float fItemHeight = pComboList->CalcItemHeight();
547 float fBorder = GetBorderSize(true);
548 float fPopupMin = 0.0f;
dsinclair2c489cc2016-11-23 16:17:20 -0800549 if (iItems > 3)
550 fPopupMin = fItemHeight * 3 + fBorder * 2;
551
Dan Sinclair05df0752017-03-14 14:43:42 -0400552 float fPopupMax = fItemHeight * iItems + fBorder * 2;
Dan Sinclairbba2a7c2017-02-07 16:36:39 -0500553 CFX_RectF rtList(m_rtClient.left, 0, m_pProperties->m_rtWidget.width, 0);
dsinclair2c489cc2016-11-23 16:17:20 -0800554 GetPopupPos(fPopupMin, fPopupMax, m_pProperties->m_rtWidget, rtList);
555
556 m_pListBox->SetWidgetRect(rtList);
557 m_pListBox->Update();
558 } else {
559 SetFocus(true);
560 }
561
dsinclair2c489cc2016-11-23 16:17:20 -0800562 if (bActivate) {
dsinclair7fa190d2016-12-07 17:23:28 -0800563 m_pListBox->RemoveStates(FWL_WGTSTATE_Invisible);
dsinclair4614b452016-12-07 17:01:58 -0800564 CFWL_Event postEvent(CFWL_Event::Type::PostDropDown, this);
dsinclair2c489cc2016-11-23 16:17:20 -0800565 DispatchEvent(&postEvent);
dsinclair7fa190d2016-12-07 17:23:28 -0800566 } else {
567 m_pListBox->SetStates(FWL_WGTSTATE_Invisible);
dsinclair2c489cc2016-11-23 16:17:20 -0800568 }
569
dsinclairda911bc2016-12-07 18:47:00 -0800570 CFX_RectF rect = m_pListBox->GetWidgetRect();
dsinclair2c489cc2016-11-23 16:17:20 -0800571 rect.Inflate(2, 2);
dsinclair43ac44c2016-12-08 14:05:14 -0800572 RepaintRect(rect);
dsinclair2c489cc2016-11-23 16:17:20 -0800573}
574
575void CFWL_ComboBox::DisForm_ModifyStylesEx(uint32_t dwStylesExAdded,
576 uint32_t dwStylesExRemoved) {
577 if (!m_pEdit)
578 DisForm_InitComboEdit();
579
580 bool bAddDropDown = !!(dwStylesExAdded & FWL_STYLEEXT_CMB_DropDown);
581 bool bDelDropDown = !!(dwStylesExRemoved & FWL_STYLEEXT_CMB_DropDown);
582
583 dwStylesExRemoved &= ~FWL_STYLEEXT_CMB_DropDown;
584 m_pProperties->m_dwStyleExes |= FWL_STYLEEXT_CMB_DropDown;
585
586 if (bAddDropDown)
587 m_pEdit->ModifyStylesEx(0, FWL_STYLEEXT_EDT_ReadOnly);
588 else if (bDelDropDown)
589 m_pEdit->ModifyStylesEx(FWL_STYLEEXT_EDT_ReadOnly, 0);
590 CFWL_Widget::ModifyStylesEx(dwStylesExAdded, dwStylesExRemoved);
591}
592
593void CFWL_ComboBox::DisForm_Update() {
594 if (m_iLock)
595 return;
596 if (m_pEdit)
597 ResetEditAlignment();
598 ResetTheme();
599 Layout();
600}
601
Dan Sinclairb45ea1f2017-02-21 14:27:59 -0500602FWL_WidgetHit CFWL_ComboBox::DisForm_HitTest(const CFX_PointF& point) {
Dan Sinclairbba2a7c2017-02-07 16:36:39 -0500603 CFX_RectF rect(0, 0, m_pProperties->m_rtWidget.width - m_rtBtn.width,
604 m_pProperties->m_rtWidget.height);
Dan Sinclairb45ea1f2017-02-21 14:27:59 -0500605 if (rect.Contains(point))
dsinclair2c489cc2016-11-23 16:17:20 -0800606 return FWL_WidgetHit::Edit;
Dan Sinclairb45ea1f2017-02-21 14:27:59 -0500607 if (m_rtBtn.Contains(point))
dsinclair2c489cc2016-11-23 16:17:20 -0800608 return FWL_WidgetHit::Client;
609 if (DisForm_IsDropListVisible()) {
dsinclairda911bc2016-12-07 18:47:00 -0800610 rect = m_pListBox->GetWidgetRect();
Dan Sinclairb45ea1f2017-02-21 14:27:59 -0500611 if (rect.Contains(point))
dsinclair2c489cc2016-11-23 16:17:20 -0800612 return FWL_WidgetHit::Client;
613 }
614 return FWL_WidgetHit::Unknown;
615}
616
Dan Sinclair2b918c82017-07-13 14:47:10 -0400617void CFWL_ComboBox::DisForm_DrawWidget(CXFA_Graphics* pGraphics,
dsinclair2c489cc2016-11-23 16:17:20 -0800618 const CFX_Matrix* pMatrix) {
619 IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
Lei Zhang0a913942017-06-01 01:37:51 -0700620 CFX_Matrix mtOrg;
dsinclair2c489cc2016-11-23 16:17:20 -0800621 if (pMatrix)
622 mtOrg = *pMatrix;
623
624 pGraphics->SaveGraphState();
625 pGraphics->ConcatMatrix(&mtOrg);
626 if (!m_rtBtn.IsEmpty(0.1f)) {
627 CFWL_ThemeBackground param;
628 param.m_pWidget = this;
629 param.m_iPart = CFWL_Part::DropDownButton;
630 param.m_dwStates = m_iBtnState;
631 param.m_pGraphics = pGraphics;
632 param.m_rtPart = m_rtBtn;
633 pTheme->DrawBackground(&param);
634 }
635 pGraphics->RestoreGraphState();
636
637 if (m_pEdit) {
dsinclairda911bc2016-12-07 18:47:00 -0800638 CFX_RectF rtEdit = m_pEdit->GetWidgetRect();
Dan Sinclairbba2a7c2017-02-07 16:36:39 -0500639 CFX_Matrix mt(1, 0, 0, 1, rtEdit.left, rtEdit.top);
dsinclair2c489cc2016-11-23 16:17:20 -0800640 mt.Concat(mtOrg);
Lei Zhang4b472142017-08-17 14:30:08 -0700641 m_pEdit->DrawWidget(pGraphics, mt);
dsinclair2c489cc2016-11-23 16:17:20 -0800642 }
643 if (m_pListBox && DisForm_IsDropListVisible()) {
dsinclairda911bc2016-12-07 18:47:00 -0800644 CFX_RectF rtList = m_pListBox->GetWidgetRect();
Dan Sinclairbba2a7c2017-02-07 16:36:39 -0500645 CFX_Matrix mt(1, 0, 0, 1, rtList.left, rtList.top);
dsinclair2c489cc2016-11-23 16:17:20 -0800646 mt.Concat(mtOrg);
Lei Zhang4b472142017-08-17 14:30:08 -0700647 m_pListBox->DrawWidget(pGraphics, mt);
dsinclair2c489cc2016-11-23 16:17:20 -0800648 }
649}
650
dsinclaira2cbc572016-12-07 18:10:16 -0800651CFX_RectF CFWL_ComboBox::DisForm_GetBBox() const {
652 CFX_RectF rect = m_pProperties->m_rtWidget;
dsinclair2c489cc2016-11-23 16:17:20 -0800653 if (!m_pListBox || !DisForm_IsDropListVisible())
dsinclaira2cbc572016-12-07 18:10:16 -0800654 return rect;
dsinclair2c489cc2016-11-23 16:17:20 -0800655
dsinclairda911bc2016-12-07 18:47:00 -0800656 CFX_RectF rtList = m_pListBox->GetWidgetRect();
dsinclair2c489cc2016-11-23 16:17:20 -0800657 rtList.Offset(rect.left, rect.top);
658 rect.Union(rtList);
dsinclaira2cbc572016-12-07 18:10:16 -0800659 return rect;
dsinclair2c489cc2016-11-23 16:17:20 -0800660}
661
662void CFWL_ComboBox::DisForm_Layout() {
dsinclair43ac44c2016-12-08 14:05:14 -0800663 m_rtClient = GetClientRect();
dsinclair2c489cc2016-11-23 16:17:20 -0800664 m_rtContent = m_rtClient;
Dan Sinclairc635c932017-01-03 15:46:55 -0500665 IFWL_ThemeProvider* theme = GetAvailableTheme();
666 if (!theme)
dsinclair2c489cc2016-11-23 16:17:20 -0800667 return;
668
Dan Sinclair05df0752017-03-14 14:43:42 -0400669 float borderWidth = 1;
670 float fBtn = theme->GetScrollBarWidth();
dsinclair2c489cc2016-11-23 16:17:20 -0800671 if (!(GetStylesEx() & FWL_STYLEEXT_CMB_ReadOnly)) {
Dan Sinclairbba2a7c2017-02-07 16:36:39 -0500672 m_rtBtn =
673 CFX_RectF(m_rtClient.right() - fBtn, m_rtClient.top + borderWidth,
674 fBtn - borderWidth, m_rtClient.height - 2 * borderWidth);
dsinclair2c489cc2016-11-23 16:17:20 -0800675 }
676
Dan Sinclairc635c932017-01-03 15:46:55 -0500677 CFWL_ThemePart part;
678 part.m_pWidget = this;
679 CFX_RectF pUIMargin = theme->GetUIMargin(&part);
680 m_rtContent.Deflate(pUIMargin.left, pUIMargin.top, pUIMargin.width,
681 pUIMargin.height);
dsinclair2c489cc2016-11-23 16:17:20 -0800682
683 if (!IsDropDownStyle() || !m_pEdit)
684 return;
685
Dan Sinclairbba2a7c2017-02-07 16:36:39 -0500686 CFX_RectF rtEdit(m_rtContent.left, m_rtContent.top, m_rtContent.width - fBtn,
687 m_rtContent.height);
dsinclair2c489cc2016-11-23 16:17:20 -0800688 m_pEdit->SetWidgetRect(rtEdit);
689
690 if (m_iCurSel >= 0) {
dsinclair2c489cc2016-11-23 16:17:20 -0800691 CFWL_ListItem* hItem = m_pListBox->GetItem(this, m_iCurSel);
dsinclair2c489cc2016-11-23 16:17:20 -0800692 m_pEdit->LockUpdate();
Dan Sinclairb38c5df2017-01-02 13:38:17 -0500693 m_pEdit->SetText(hItem ? hItem->GetText() : L"");
dsinclair2c489cc2016-11-23 16:17:20 -0800694 m_pEdit->UnlockUpdate();
695 }
696 m_pEdit->Update();
697}
698
699void CFWL_ComboBox::OnProcessMessage(CFWL_Message* pMessage) {
700 if (m_pWidgetMgr->IsFormDisabled()) {
701 DisForm_OnProcessMessage(pMessage);
702 return;
703 }
704 if (!pMessage)
705 return;
706
dsinclair4614b452016-12-07 17:01:58 -0800707 switch (pMessage->GetType()) {
708 case CFWL_Message::Type::SetFocus:
dsinclair2c489cc2016-11-23 16:17:20 -0800709 OnFocusChanged(pMessage, true);
710 break;
dsinclair4614b452016-12-07 17:01:58 -0800711 case CFWL_Message::Type::KillFocus:
dsinclair2c489cc2016-11-23 16:17:20 -0800712 OnFocusChanged(pMessage, false);
713 break;
dsinclair4614b452016-12-07 17:01:58 -0800714 case CFWL_Message::Type::Mouse: {
dsinclair447b1f32016-12-08 10:06:32 -0800715 CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
dsinclair2c489cc2016-11-23 16:17:20 -0800716 switch (pMsg->m_dwCmd) {
717 case FWL_MouseCommand::LeftButtonDown:
718 OnLButtonDown(pMsg);
719 break;
720 case FWL_MouseCommand::LeftButtonUp:
721 OnLButtonUp(pMsg);
722 break;
723 case FWL_MouseCommand::Move:
724 OnMouseMove(pMsg);
725 break;
726 case FWL_MouseCommand::Leave:
727 OnMouseLeave(pMsg);
728 break;
729 default:
730 break;
731 }
732 break;
733 }
dsinclair4614b452016-12-07 17:01:58 -0800734 case CFWL_Message::Type::Key:
dsinclair447b1f32016-12-08 10:06:32 -0800735 OnKey(static_cast<CFWL_MessageKey*>(pMessage));
dsinclair2c489cc2016-11-23 16:17:20 -0800736 break;
737 default:
738 break;
739 }
740
741 CFWL_Widget::OnProcessMessage(pMessage);
742}
743
744void CFWL_ComboBox::OnProcessEvent(CFWL_Event* pEvent) {
dsinclair4614b452016-12-07 17:01:58 -0800745 CFWL_Event::Type type = pEvent->GetType();
746 if (type == CFWL_Event::Type::Scroll) {
dsinclair447b1f32016-12-08 10:06:32 -0800747 CFWL_EventScroll* pScrollEvent = static_cast<CFWL_EventScroll*>(pEvent);
748 CFWL_EventScroll pScrollEv(this);
dsinclair2c489cc2016-11-23 16:17:20 -0800749 pScrollEv.m_iScrollCode = pScrollEvent->m_iScrollCode;
750 pScrollEv.m_fPos = pScrollEvent->m_fPos;
751 DispatchEvent(&pScrollEv);
dsinclair4614b452016-12-07 17:01:58 -0800752 } else if (type == CFWL_Event::Type::TextChanged) {
753 CFWL_Event pTemp(CFWL_Event::Type::EditChanged, this);
dsinclair2c489cc2016-11-23 16:17:20 -0800754 DispatchEvent(&pTemp);
755 }
756}
757
Dan Sinclair2b918c82017-07-13 14:47:10 -0400758void CFWL_ComboBox::OnDrawWidget(CXFA_Graphics* pGraphics,
Lei Zhang4b472142017-08-17 14:30:08 -0700759 const CFX_Matrix& matrix) {
760 DrawWidget(pGraphics, matrix);
dsinclair2c489cc2016-11-23 16:17:20 -0800761}
762
763void CFWL_ComboBox::OnFocusChanged(CFWL_Message* pMsg, bool bSet) {
764 if (bSet) {
765 m_pProperties->m_dwStates |= FWL_WGTSTATE_Focused;
766 if (IsDropDownStyle() && pMsg->m_pSrcTarget != m_pListBox.get()) {
767 if (!m_pEdit)
768 return;
769 m_pEdit->SetSelected();
770 return;
771 }
772
dsinclair43ac44c2016-12-08 14:05:14 -0800773 RepaintRect(m_rtClient);
dsinclair2c489cc2016-11-23 16:17:20 -0800774 return;
775 }
776
777 m_pProperties->m_dwStates &= ~FWL_WGTSTATE_Focused;
778 if (!IsDropDownStyle() || pMsg->m_pDstTarget == m_pListBox.get()) {
dsinclair43ac44c2016-12-08 14:05:14 -0800779 RepaintRect(m_rtClient);
dsinclair2c489cc2016-11-23 16:17:20 -0800780 return;
781 }
782 if (!m_pEdit)
783 return;
784
785 m_pEdit->FlagFocus(false);
786 m_pEdit->ClearSelected();
787}
788
dsinclair447b1f32016-12-08 10:06:32 -0800789void CFWL_ComboBox::OnLButtonDown(CFWL_MessageMouse* pMsg) {
dsinclair2c489cc2016-11-23 16:17:20 -0800790 if (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled)
791 return;
792
793 CFX_RectF& rtBtn = IsDropDownStyle() ? m_rtBtn : m_rtClient;
Dan Sinclairb45ea1f2017-02-21 14:27:59 -0500794 if (!rtBtn.Contains(pMsg->m_pos))
dsinclair2c489cc2016-11-23 16:17:20 -0800795 return;
796
797 if (IsDropDownStyle() && m_pEdit)
798 MatchEditText();
799
800 m_bLButtonDown = true;
801 m_iBtnState = CFWL_PartState_Pressed;
dsinclair43ac44c2016-12-08 14:05:14 -0800802 RepaintRect(m_rtClient);
dsinclair2c489cc2016-11-23 16:17:20 -0800803
804 ShowDropList(true);
805 m_iBtnState = CFWL_PartState_Normal;
dsinclair43ac44c2016-12-08 14:05:14 -0800806 RepaintRect(m_rtClient);
dsinclair2c489cc2016-11-23 16:17:20 -0800807}
808
dsinclair447b1f32016-12-08 10:06:32 -0800809void CFWL_ComboBox::OnLButtonUp(CFWL_MessageMouse* pMsg) {
dsinclair2c489cc2016-11-23 16:17:20 -0800810 m_bLButtonDown = false;
Dan Sinclairb45ea1f2017-02-21 14:27:59 -0500811 if (m_rtBtn.Contains(pMsg->m_pos))
dsinclair2c489cc2016-11-23 16:17:20 -0800812 m_iBtnState = CFWL_PartState_Hovered;
813 else
814 m_iBtnState = CFWL_PartState_Normal;
815
dsinclair43ac44c2016-12-08 14:05:14 -0800816 RepaintRect(m_rtBtn);
dsinclair2c489cc2016-11-23 16:17:20 -0800817}
818
dsinclair447b1f32016-12-08 10:06:32 -0800819void CFWL_ComboBox::OnMouseMove(CFWL_MessageMouse* pMsg) {
dsinclair2c489cc2016-11-23 16:17:20 -0800820 int32_t iOldState = m_iBtnState;
Dan Sinclairb45ea1f2017-02-21 14:27:59 -0500821 if (m_rtBtn.Contains(pMsg->m_pos)) {
dsinclair2c489cc2016-11-23 16:17:20 -0800822 m_iBtnState =
823 m_bLButtonDown ? CFWL_PartState_Pressed : CFWL_PartState_Hovered;
824 } else {
825 m_iBtnState = CFWL_PartState_Normal;
826 }
827 if ((iOldState != m_iBtnState) &&
828 !((m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled) ==
829 FWL_WGTSTATE_Disabled)) {
dsinclair43ac44c2016-12-08 14:05:14 -0800830 RepaintRect(m_rtBtn);
dsinclair2c489cc2016-11-23 16:17:20 -0800831 }
832}
833
dsinclair447b1f32016-12-08 10:06:32 -0800834void CFWL_ComboBox::OnMouseLeave(CFWL_MessageMouse* pMsg) {
dsinclair2c489cc2016-11-23 16:17:20 -0800835 if (!IsDropListVisible() &&
836 !((m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled) ==
837 FWL_WGTSTATE_Disabled)) {
838 m_iBtnState = CFWL_PartState_Normal;
dsinclair43ac44c2016-12-08 14:05:14 -0800839 RepaintRect(m_rtBtn);
dsinclair2c489cc2016-11-23 16:17:20 -0800840 }
841}
842
dsinclair447b1f32016-12-08 10:06:32 -0800843void CFWL_ComboBox::OnKey(CFWL_MessageKey* pMsg) {
dsinclair2c489cc2016-11-23 16:17:20 -0800844 uint32_t dwKeyCode = pMsg->m_dwKeyCode;
dsinclair4614b452016-12-07 17:01:58 -0800845 if (dwKeyCode == FWL_VKEY_Tab)
dsinclair2c489cc2016-11-23 16:17:20 -0800846 return;
dsinclair2c489cc2016-11-23 16:17:20 -0800847 if (pMsg->m_pDstTarget == this)
848 DoSubCtrlKey(pMsg);
849}
850
dsinclair447b1f32016-12-08 10:06:32 -0800851void CFWL_ComboBox::DoSubCtrlKey(CFWL_MessageKey* pMsg) {
dsinclair2c489cc2016-11-23 16:17:20 -0800852 uint32_t dwKeyCode = pMsg->m_dwKeyCode;
853 const bool bUp = dwKeyCode == FWL_VKEY_Up;
854 const bool bDown = dwKeyCode == FWL_VKEY_Down;
855 if (bUp || bDown) {
856 int32_t iCount = m_pListBox->CountItems(nullptr);
857 if (iCount < 1)
858 return;
859
860 bool bMatchEqual = false;
861 int32_t iCurSel = m_iCurSel;
862 bool bDropDown = IsDropDownStyle();
863 if (bDropDown && m_pEdit) {
dan sinclair0354ccf2016-11-24 10:45:29 -0500864 CFX_WideString wsText = m_pEdit->GetText();
dsinclair2c489cc2016-11-23 16:17:20 -0800865 iCurSel = m_pListBox->MatchItem(wsText);
866 if (iCurSel >= 0) {
dsinclair2c489cc2016-11-23 16:17:20 -0800867 CFWL_ListItem* hItem = m_pListBox->GetItem(this, iCurSel);
Dan Sinclairb38c5df2017-01-02 13:38:17 -0500868 bMatchEqual = wsText == (hItem ? hItem->GetText() : L"");
dsinclair2c489cc2016-11-23 16:17:20 -0800869 }
870 }
871 if (iCurSel < 0) {
872 iCurSel = 0;
873 } else if (!bDropDown || bMatchEqual) {
874 if ((bUp && iCurSel == 0) || (bDown && iCurSel == iCount - 1))
875 return;
876 if (bUp)
877 iCurSel--;
878 else
879 iCurSel++;
880 }
881 m_iCurSel = iCurSel;
882 if (bDropDown && m_pEdit)
883 SyncEditText(m_iCurSel);
884 else
dsinclair43ac44c2016-12-08 14:05:14 -0800885 RepaintRect(m_rtClient);
dsinclair2c489cc2016-11-23 16:17:20 -0800886 return;
887 }
888
889 if (IsDropDownStyle())
890 m_pEdit->GetDelegate()->OnProcessMessage(pMsg);
891}
892
893void CFWL_ComboBox::DisForm_OnProcessMessage(CFWL_Message* pMessage) {
894 if (!pMessage)
895 return;
896
897 bool backDefault = true;
dsinclair4614b452016-12-07 17:01:58 -0800898 switch (pMessage->GetType()) {
899 case CFWL_Message::Type::SetFocus: {
dsinclair2c489cc2016-11-23 16:17:20 -0800900 backDefault = false;
901 DisForm_OnFocusChanged(pMessage, true);
902 break;
903 }
dsinclair4614b452016-12-07 17:01:58 -0800904 case CFWL_Message::Type::KillFocus: {
dsinclair2c489cc2016-11-23 16:17:20 -0800905 backDefault = false;
906 DisForm_OnFocusChanged(pMessage, false);
907 break;
908 }
dsinclair4614b452016-12-07 17:01:58 -0800909 case CFWL_Message::Type::Mouse: {
dsinclair2c489cc2016-11-23 16:17:20 -0800910 backDefault = false;
dsinclair447b1f32016-12-08 10:06:32 -0800911 CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
dsinclair2c489cc2016-11-23 16:17:20 -0800912 switch (pMsg->m_dwCmd) {
913 case FWL_MouseCommand::LeftButtonDown:
914 DisForm_OnLButtonDown(pMsg);
915 break;
916 case FWL_MouseCommand::LeftButtonUp:
917 OnLButtonUp(pMsg);
918 break;
919 default:
920 break;
921 }
922 break;
923 }
dsinclair4614b452016-12-07 17:01:58 -0800924 case CFWL_Message::Type::Key: {
dsinclair2c489cc2016-11-23 16:17:20 -0800925 backDefault = false;
dsinclair447b1f32016-12-08 10:06:32 -0800926 CFWL_MessageKey* pKey = static_cast<CFWL_MessageKey*>(pMessage);
dsinclair2c489cc2016-11-23 16:17:20 -0800927 if (pKey->m_dwCmd == FWL_KeyCommand::KeyUp)
928 break;
929 if (DisForm_IsDropListVisible() &&
930 pKey->m_dwCmd == FWL_KeyCommand::KeyDown) {
931 bool bListKey = pKey->m_dwKeyCode == FWL_VKEY_Up ||
932 pKey->m_dwKeyCode == FWL_VKEY_Down ||
933 pKey->m_dwKeyCode == FWL_VKEY_Return ||
934 pKey->m_dwKeyCode == FWL_VKEY_Escape;
935 if (bListKey) {
936 m_pListBox->GetDelegate()->OnProcessMessage(pMessage);
937 break;
938 }
939 }
940 DisForm_OnKey(pKey);
941 break;
942 }
943 default:
944 break;
945 }
946 if (backDefault)
947 CFWL_Widget::OnProcessMessage(pMessage);
948}
949
dsinclair447b1f32016-12-08 10:06:32 -0800950void CFWL_ComboBox::DisForm_OnLButtonDown(CFWL_MessageMouse* pMsg) {
dsinclair2c489cc2016-11-23 16:17:20 -0800951 bool bDropDown = DisForm_IsDropListVisible();
952 CFX_RectF& rtBtn = bDropDown ? m_rtBtn : m_rtClient;
Dan Sinclairb45ea1f2017-02-21 14:27:59 -0500953 if (!rtBtn.Contains(pMsg->m_pos))
dsinclair2c489cc2016-11-23 16:17:20 -0800954 return;
955
956 if (DisForm_IsDropListVisible()) {
957 DisForm_ShowDropList(false);
958 return;
959 }
960 if (m_pEdit)
961 MatchEditText();
962 DisForm_ShowDropList(true);
963}
964
965void CFWL_ComboBox::DisForm_OnFocusChanged(CFWL_Message* pMsg, bool bSet) {
966 if (bSet) {
967 m_pProperties->m_dwStates |= FWL_WGTSTATE_Focused;
968 if ((m_pEdit->GetStates() & FWL_WGTSTATE_Focused) == 0) {
dsinclair447b1f32016-12-08 10:06:32 -0800969 CFWL_MessageSetFocus msg(nullptr, m_pEdit.get());
dsinclair2c489cc2016-11-23 16:17:20 -0800970 m_pEdit->GetDelegate()->OnProcessMessage(&msg);
971 }
972 } else {
973 m_pProperties->m_dwStates &= ~FWL_WGTSTATE_Focused;
974 DisForm_ShowDropList(false);
dsinclair447b1f32016-12-08 10:06:32 -0800975 CFWL_MessageKillFocus msg(m_pEdit.get());
dsinclair2c489cc2016-11-23 16:17:20 -0800976 m_pEdit->GetDelegate()->OnProcessMessage(&msg);
977 }
978}
979
dsinclair447b1f32016-12-08 10:06:32 -0800980void CFWL_ComboBox::DisForm_OnKey(CFWL_MessageKey* pMsg) {
dsinclair2c489cc2016-11-23 16:17:20 -0800981 uint32_t dwKeyCode = pMsg->m_dwKeyCode;
982 const bool bUp = dwKeyCode == FWL_VKEY_Up;
983 const bool bDown = dwKeyCode == FWL_VKEY_Down;
984 if (bUp || bDown) {
985 CFWL_ComboList* pComboList = m_pListBox.get();
986 int32_t iCount = pComboList->CountItems(nullptr);
987 if (iCount < 1)
988 return;
989
990 bool bMatchEqual = false;
991 int32_t iCurSel = m_iCurSel;
992 if (m_pEdit) {
dan sinclair0354ccf2016-11-24 10:45:29 -0500993 CFX_WideString wsText = m_pEdit->GetText();
dsinclair2c489cc2016-11-23 16:17:20 -0800994 iCurSel = pComboList->MatchItem(wsText);
995 if (iCurSel >= 0) {
dsinclair2c489cc2016-11-23 16:17:20 -0800996 CFWL_ListItem* item = m_pListBox->GetSelItem(iCurSel);
Dan Sinclairb38c5df2017-01-02 13:38:17 -0500997 bMatchEqual = wsText == (item ? item->GetText() : L"");
dsinclair2c489cc2016-11-23 16:17:20 -0800998 }
999 }
1000 if (iCurSel < 0) {
1001 iCurSel = 0;
1002 } else if (bMatchEqual) {
1003 if ((bUp && iCurSel == 0) || (bDown && iCurSel == iCount - 1))
1004 return;
1005 if (bUp)
1006 iCurSel--;
1007 else
1008 iCurSel++;
1009 }
1010 m_iCurSel = iCurSel;
1011 SyncEditText(m_iCurSel);
1012 return;
1013 }
1014 if (m_pEdit)
1015 m_pEdit->GetDelegate()->OnProcessMessage(pMsg);
Tom Sepez99ffdb02016-01-26 14:51:21 -08001016}