Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(273)

Side by Side Diff: xfa/fwl/core/ifwl_combobox.cpp

Issue 2524173002: Merge IFWL and CFWL classes. (Closed)
Patch Set: make chrome build happy Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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/fwl/core/ifwl_combobox.h"
8
9 #include <algorithm>
10 #include <memory>
11 #include <utility>
12
13 #include "third_party/base/ptr_util.h"
14 #include "xfa/fde/cfde_txtedtengine.h"
15 #include "xfa/fde/tto/fde_textout.h"
16 #include "xfa/fwl/core/cfwl_app.h"
17 #include "xfa/fwl/core/cfwl_evteditchanged.h"
18 #include "xfa/fwl/core/cfwl_evtpostdropdown.h"
19 #include "xfa/fwl/core/cfwl_evtpredropdown.h"
20 #include "xfa/fwl/core/cfwl_evtselectchanged.h"
21 #include "xfa/fwl/core/cfwl_evttextchanged.h"
22 #include "xfa/fwl/core/cfwl_formproxy.h"
23 #include "xfa/fwl/core/cfwl_msgkey.h"
24 #include "xfa/fwl/core/cfwl_msgkillfocus.h"
25 #include "xfa/fwl/core/cfwl_msgmouse.h"
26 #include "xfa/fwl/core/cfwl_msgsetfocus.h"
27 #include "xfa/fwl/core/cfwl_notedriver.h"
28 #include "xfa/fwl/core/cfwl_themebackground.h"
29 #include "xfa/fwl/core/cfwl_themepart.h"
30 #include "xfa/fwl/core/cfwl_themetext.h"
31 #include "xfa/fwl/core/cfwl_widgetmgr.h"
32 #include "xfa/fwl/core/ifwl_listbox.h"
33 #include "xfa/fwl/core/ifwl_themeprovider.h"
34
35 IFWL_ComboBox::IFWL_ComboBox(const CFWL_App* app,
36 std::unique_ptr<CFWL_WidgetProperties> properties)
37 : IFWL_Widget(app, std::move(properties), nullptr),
38 m_pComboBoxProxy(nullptr),
39 m_bLButtonDown(false),
40 m_iCurSel(-1),
41 m_iBtnState(CFWL_PartState_Normal),
42 m_fComboFormHandler(0) {
43 m_rtClient.Reset();
44 m_rtBtn.Reset();
45 m_rtHandler.Reset();
46
47 if (m_pWidgetMgr->IsFormDisabled()) {
48 DisForm_InitComboList();
49 DisForm_InitComboEdit();
50 return;
51 }
52
53 auto prop = pdfium::MakeUnique<CFWL_WidgetProperties>();
54 prop->m_pThemeProvider = m_pProperties->m_pThemeProvider;
55 prop->m_dwStyles |= FWL_WGTSTYLE_Border | FWL_WGTSTYLE_VScroll;
56 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_CMB_ListItemIconText)
57 prop->m_dwStyleExes |= FWL_STYLEEXT_LTB_Icon;
58 m_pListBox =
59 pdfium::MakeUnique<CFWL_ComboList>(m_pOwnerApp, std::move(prop), this);
60
61 if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_CMB_DropDown) && !m_pEdit) {
62 m_pEdit.reset(new CFWL_ComboEdit(
63 m_pOwnerApp, pdfium::MakeUnique<CFWL_WidgetProperties>(), this));
64 m_pEdit->SetOuter(this);
65 }
66 if (m_pEdit)
67 m_pEdit->SetParent(this);
68
69 SetStates(m_pProperties->m_dwStates);
70 }
71
72 IFWL_ComboBox::~IFWL_ComboBox() {}
73
74 FWL_Type IFWL_ComboBox::GetClassID() const {
75 return FWL_Type::ComboBox;
76 }
77
78 void IFWL_ComboBox::GetWidgetRect(CFX_RectF& rect, bool bAutoSize) {
79 if (!bAutoSize) {
80 rect = m_pProperties->m_rtWidget;
81 return;
82 }
83
84 rect.Reset();
85 if (IsDropDownStyle() && m_pEdit) {
86 m_pEdit->GetWidgetRect(rect, true);
87 } else {
88 rect.width = 100;
89 rect.height = 16;
90 }
91 if (!m_pProperties->m_pThemeProvider)
92 ResetTheme();
93
94 FX_FLOAT* pFWidth = static_cast<FX_FLOAT*>(
95 GetThemeCapacity(CFWL_WidgetCapacity::ScrollBarWidth));
96 if (!pFWidth)
97 return;
98
99 rect.Inflate(0, 0, *pFWidth, 0);
100 IFWL_Widget::GetWidgetRect(rect, true);
101 }
102
103 void IFWL_ComboBox::AddString(const CFX_WideStringC& wsText) {
104 m_pListBox->AddString(wsText);
105 }
106
107 bool IFWL_ComboBox::RemoveAt(int32_t iIndex) {
108 return m_pListBox->RemoveAt(iIndex);
109 }
110
111 void IFWL_ComboBox::RemoveAll() {
112 m_pListBox->DeleteAll();
113 }
114
115 void IFWL_ComboBox::ModifyStylesEx(uint32_t dwStylesExAdded,
116 uint32_t dwStylesExRemoved) {
117 if (m_pWidgetMgr->IsFormDisabled()) {
118 DisForm_ModifyStylesEx(dwStylesExAdded, dwStylesExRemoved);
119 return;
120 }
121
122 bool bAddDropDown = !!(dwStylesExAdded & FWL_STYLEEXT_CMB_DropDown);
123 bool bRemoveDropDown = !!(dwStylesExRemoved & FWL_STYLEEXT_CMB_DropDown);
124 if (bAddDropDown && !m_pEdit) {
125 m_pEdit = pdfium::MakeUnique<CFWL_ComboEdit>(
126 m_pOwnerApp, pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr);
127 m_pEdit->SetOuter(this);
128 m_pEdit->SetParent(this);
129 } else if (bRemoveDropDown && m_pEdit) {
130 m_pEdit->SetStates(FWL_WGTSTATE_Invisible, true);
131 }
132 IFWL_Widget::ModifyStylesEx(dwStylesExAdded, dwStylesExRemoved);
133 }
134
135 void IFWL_ComboBox::Update() {
136 if (m_pWidgetMgr->IsFormDisabled()) {
137 DisForm_Update();
138 return;
139 }
140 if (IsLocked())
141 return;
142
143 ResetTheme();
144 if (IsDropDownStyle() && m_pEdit)
145 ResetEditAlignment();
146 if (!m_pProperties->m_pThemeProvider)
147 m_pProperties->m_pThemeProvider = GetAvailableTheme();
148
149 Layout();
150 CFWL_ThemePart part;
151 part.m_pWidget = this;
152 m_fComboFormHandler =
153 *static_cast<FX_FLOAT*>(m_pProperties->m_pThemeProvider->GetCapacity(
154 &part, CFWL_WidgetCapacity::ComboFormHandler));
155 }
156
157 FWL_WidgetHit IFWL_ComboBox::HitTest(FX_FLOAT fx, FX_FLOAT fy) {
158 if (m_pWidgetMgr->IsFormDisabled())
159 return DisForm_HitTest(fx, fy);
160 return IFWL_Widget::HitTest(fx, fy);
161 }
162
163 void IFWL_ComboBox::DrawWidget(CFX_Graphics* pGraphics,
164 const CFX_Matrix* pMatrix) {
165 if (m_pWidgetMgr->IsFormDisabled()) {
166 DisForm_DrawWidget(pGraphics, pMatrix);
167 return;
168 }
169
170 if (!pGraphics)
171 return;
172 if (!m_pProperties->m_pThemeProvider)
173 return;
174
175 IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
176 if (HasBorder())
177 DrawBorder(pGraphics, CFWL_Part::Border, pTheme, pMatrix);
178 if (HasEdge())
179 DrawEdge(pGraphics, CFWL_Part::Edge, pTheme, pMatrix);
180
181 if (!IsDropDownStyle()) {
182 CFX_RectF rtTextBk(m_rtClient);
183 rtTextBk.width -= m_rtBtn.width;
184
185 CFWL_ThemeBackground param;
186 param.m_pWidget = this;
187 param.m_iPart = CFWL_Part::Background;
188 param.m_pGraphics = pGraphics;
189 if (pMatrix)
190 param.m_matrix.Concat(*pMatrix);
191 param.m_rtPart = rtTextBk;
192
193 if (m_iCurSel >= 0) {
194 if (void* p = m_pListBox->GetItemData(
195 m_pListBox.get(),
196 m_pListBox->GetItem(m_pListBox.get(), m_iCurSel))) {
197 param.m_pData = p;
198 }
199 }
200
201 if (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled) {
202 param.m_dwStates = CFWL_PartState_Disabled;
203 } else if ((m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) &&
204 (m_iCurSel >= 0)) {
205 param.m_dwStates = CFWL_PartState_Selected;
206 } else {
207 param.m_dwStates = CFWL_PartState_Normal;
208 }
209 pTheme->DrawBackground(&param);
210
211 if (m_iCurSel >= 0) {
212 if (!m_pListBox)
213 return;
214
215 CFX_WideString wsText;
216 CFWL_ListItem* hItem = m_pListBox->GetItem(this, m_iCurSel);
217 m_pListBox->GetDataProviderItemText(hItem, wsText);
218
219 CFWL_ThemeText theme_text;
220 theme_text.m_pWidget = this;
221 theme_text.m_iPart = CFWL_Part::Caption;
222 theme_text.m_dwStates = m_iBtnState;
223 theme_text.m_pGraphics = pGraphics;
224 theme_text.m_matrix.Concat(*pMatrix);
225 theme_text.m_rtPart = rtTextBk;
226 theme_text.m_dwStates = (m_pProperties->m_dwStates & FWL_WGTSTATE_Focused)
227 ? CFWL_PartState_Selected
228 : CFWL_PartState_Normal;
229 theme_text.m_wsText = wsText;
230 theme_text.m_dwTTOStyles = FDE_TTOSTYLE_SingleLine;
231 theme_text.m_iTTOAlign = FDE_TTOALIGNMENT_CenterLeft;
232 pTheme->DrawText(&theme_text);
233 }
234 }
235
236 CFWL_ThemeBackground param;
237 param.m_pWidget = this;
238 param.m_iPart = CFWL_Part::DropDownButton;
239 param.m_dwStates = (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled)
240 ? CFWL_PartState_Disabled
241 : m_iBtnState;
242 param.m_pGraphics = pGraphics;
243 param.m_matrix.Concat(*pMatrix);
244 param.m_rtPart = m_rtBtn;
245 pTheme->DrawBackground(&param);
246 }
247
248 void IFWL_ComboBox::SetThemeProvider(IFWL_ThemeProvider* pThemeProvider) {
249 if (!pThemeProvider)
250 return;
251
252 m_pProperties->m_pThemeProvider = pThemeProvider;
253 if (m_pListBox)
254 m_pListBox->SetThemeProvider(pThemeProvider);
255 if (m_pEdit)
256 m_pEdit->SetThemeProvider(pThemeProvider);
257 }
258
259 void IFWL_ComboBox::GetTextByIndex(int32_t iIndex,
260 CFX_WideString& wsText) const {
261 CFWL_ListItem* pItem = static_cast<CFWL_ListItem*>(
262 m_pListBox->GetItem(m_pListBox.get(), iIndex));
263 if (pItem)
264 wsText = pItem->m_wsText;
265 }
266
267 void IFWL_ComboBox::SetCurSel(int32_t iSel) {
268 int32_t iCount = m_pListBox->CountItems(nullptr);
269 bool bClearSel = iSel < 0 || iSel >= iCount;
270 if (IsDropDownStyle() && m_pEdit) {
271 if (bClearSel) {
272 m_pEdit->SetText(CFX_WideString());
273 } else {
274 CFX_WideString wsText;
275 CFWL_ListItem* hItem = m_pListBox->GetItem(this, iSel);
276 m_pListBox->GetDataProviderItemText(hItem, wsText);
277 m_pEdit->SetText(wsText);
278 }
279 m_pEdit->Update();
280 }
281 m_iCurSel = bClearSel ? -1 : iSel;
282 }
283
284 void IFWL_ComboBox::SetStates(uint32_t dwStates, bool bSet) {
285 if (IsDropDownStyle() && m_pEdit)
286 m_pEdit->SetStates(dwStates, bSet);
287 if (m_pListBox)
288 m_pListBox->SetStates(dwStates, bSet);
289 IFWL_Widget::SetStates(dwStates, bSet);
290 }
291
292 void IFWL_ComboBox::SetEditText(const CFX_WideString& wsText) {
293 if (!m_pEdit)
294 return;
295
296 m_pEdit->SetText(wsText);
297 m_pEdit->Update();
298 }
299
300 void IFWL_ComboBox::GetEditText(CFX_WideString& wsText,
301 int32_t nStart,
302 int32_t nCount) const {
303 if (m_pEdit) {
304 m_pEdit->GetText(wsText, nStart, nCount);
305 return;
306 }
307 if (!m_pListBox)
308 return;
309
310 CFWL_ListItem* hItem = m_pListBox->GetItem(this, m_iCurSel);
311 m_pListBox->GetDataProviderItemText(hItem, wsText);
312 }
313
314 void IFWL_ComboBox::OpenDropDownList(bool bActivate) {
315 ShowDropList(bActivate);
316 }
317
318 void IFWL_ComboBox::GetBBox(CFX_RectF& rect) const {
319 if (m_pWidgetMgr->IsFormDisabled()) {
320 DisForm_GetBBox(rect);
321 return;
322 }
323
324 rect = m_pProperties->m_rtWidget;
325 if (!m_pListBox || !IsDropListVisible())
326 return;
327
328 CFX_RectF rtList;
329 m_pListBox->GetWidgetRect(rtList);
330 rtList.Offset(rect.left, rect.top);
331 rect.Union(rtList);
332 }
333
334 void IFWL_ComboBox::EditModifyStylesEx(uint32_t dwStylesExAdded,
335 uint32_t dwStylesExRemoved) {
336 if (m_pEdit)
337 m_pEdit->ModifyStylesEx(dwStylesExAdded, dwStylesExRemoved);
338 }
339
340 void IFWL_ComboBox::DrawStretchHandler(CFX_Graphics* pGraphics,
341 const CFX_Matrix* pMatrix) {
342 CFWL_ThemeBackground param;
343 param.m_pGraphics = pGraphics;
344 param.m_iPart = CFWL_Part::StretchHandler;
345 param.m_dwStates = CFWL_PartState_Normal;
346 param.m_pWidget = this;
347 if (pMatrix)
348 param.m_matrix.Concat(*pMatrix);
349 param.m_rtPart = m_rtHandler;
350 m_pProperties->m_pThemeProvider->DrawBackground(&param);
351 }
352
353 void IFWL_ComboBox::ShowDropList(bool bActivate) {
354 if (m_pWidgetMgr->IsFormDisabled())
355 return DisForm_ShowDropList(bActivate);
356 if (IsDropListVisible() == bActivate)
357 return;
358 if (!m_pComboBoxProxy)
359 InitProxyForm();
360
361 m_pComboBoxProxy->Reset();
362 if (!bActivate) {
363 m_pComboBoxProxy->EndDoModal();
364
365 m_bLButtonDown = false;
366 m_pListBox->SetNotifyOwner(true);
367 SetFocus(true);
368 return;
369 }
370
371 m_pListBox->ChangeSelected(m_iCurSel);
372 ResetListItemAlignment();
373
374 uint32_t dwStyleAdd = m_pProperties->m_dwStyleExes &
375 (FWL_STYLEEXT_CMB_Sort | FWL_STYLEEXT_CMB_OwnerDraw);
376 m_pListBox->ModifyStylesEx(dwStyleAdd, 0);
377 m_pListBox->GetWidgetRect(m_rtList, true);
378
379 CFX_RectF rtAnchor;
380 rtAnchor.Set(0, 0, m_pProperties->m_rtWidget.width,
381 m_pProperties->m_rtWidget.height);
382
383 m_rtList.width = std::max(m_rtList.width, m_rtClient.width);
384 m_rtProxy = m_rtList;
385 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_CMB_ListDrag)
386 m_rtProxy.height += m_fComboFormHandler;
387
388 GetPopupPos(0, m_rtProxy.height, rtAnchor, m_rtProxy);
389 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_CMB_ListDrag) {
390 FX_FLOAT fx = 0;
391 FX_FLOAT fy = m_rtClient.top + m_rtClient.height / 2;
392 TransformTo(nullptr, fx, fy);
393
394 m_bUpFormHandler = fy > m_rtProxy.top;
395 if (m_bUpFormHandler) {
396 m_rtHandler.Set(0, 0, m_rtList.width, m_fComboFormHandler);
397 m_rtList.top = m_fComboFormHandler;
398 } else {
399 m_rtHandler.Set(0, m_rtList.height, m_rtList.width, m_fComboFormHandler);
400 }
401 }
402 m_pComboBoxProxy->SetWidgetRect(m_rtProxy);
403 m_pComboBoxProxy->Update();
404 m_pListBox->SetWidgetRect(m_rtList);
405 m_pListBox->Update();
406
407 CFWL_EvtPreDropDown ev;
408 ev.m_pSrcTarget = this;
409 DispatchEvent(&ev);
410
411 m_fItemHeight = m_pListBox->GetItemHeight();
412 m_pListBox->SetFocus(true);
413 m_pComboBoxProxy->DoModal();
414 m_pListBox->SetFocus(false);
415 }
416
417 void IFWL_ComboBox::MatchEditText() {
418 CFX_WideString wsText;
419 m_pEdit->GetText(wsText);
420 int32_t iMatch = m_pListBox->MatchItem(wsText);
421 if (iMatch != m_iCurSel) {
422 m_pListBox->ChangeSelected(iMatch);
423 if (iMatch >= 0)
424 SyncEditText(iMatch);
425 } else if (iMatch >= 0) {
426 m_pEdit->SetSelected();
427 }
428 m_iCurSel = iMatch;
429 }
430
431 void IFWL_ComboBox::SyncEditText(int32_t iListItem) {
432 CFX_WideString wsText;
433 CFWL_ListItem* hItem = m_pListBox->GetItem(this, iListItem);
434 m_pListBox->GetDataProviderItemText(hItem, wsText);
435 m_pEdit->SetText(wsText);
436 m_pEdit->Update();
437 m_pEdit->SetSelected();
438 }
439
440 void IFWL_ComboBox::Layout() {
441 if (m_pWidgetMgr->IsFormDisabled())
442 return DisForm_Layout();
443
444 GetClientRect(m_rtClient);
445 FX_FLOAT* pFWidth = static_cast<FX_FLOAT*>(
446 GetThemeCapacity(CFWL_WidgetCapacity::ScrollBarWidth));
447 if (!pFWidth)
448 return;
449
450 FX_FLOAT fBtn = *pFWidth;
451 m_rtBtn.Set(m_rtClient.right() - fBtn, m_rtClient.top, fBtn,
452 m_rtClient.height);
453 if (!IsDropDownStyle() || !m_pEdit)
454 return;
455
456 CFX_RectF rtEdit;
457 rtEdit.Set(m_rtClient.left, m_rtClient.top, m_rtClient.width - fBtn,
458 m_rtClient.height);
459 m_pEdit->SetWidgetRect(rtEdit);
460
461 if (m_iCurSel >= 0) {
462 CFX_WideString wsText;
463 CFWL_ListItem* hItem = m_pListBox->GetItem(this, m_iCurSel);
464 m_pListBox->GetDataProviderItemText(hItem, wsText);
465 m_pEdit->LockUpdate();
466 m_pEdit->SetText(wsText);
467 m_pEdit->UnlockUpdate();
468 }
469 m_pEdit->Update();
470 }
471
472 void IFWL_ComboBox::ResetTheme() {
473 IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
474 if (!pTheme) {
475 pTheme = GetAvailableTheme();
476 m_pProperties->m_pThemeProvider = pTheme;
477 }
478 if (m_pListBox && !m_pListBox->GetThemeProvider())
479 m_pListBox->SetThemeProvider(pTheme);
480 if (m_pEdit && !m_pEdit->GetThemeProvider())
481 m_pEdit->SetThemeProvider(pTheme);
482 }
483
484 void IFWL_ComboBox::ResetEditAlignment() {
485 if (!m_pEdit)
486 return;
487
488 uint32_t dwAdd = 0;
489 switch (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_CMB_EditHAlignMask) {
490 case FWL_STYLEEXT_CMB_EditHCenter: {
491 dwAdd |= FWL_STYLEEXT_EDT_HCenter;
492 break;
493 }
494 case FWL_STYLEEXT_CMB_EditHFar: {
495 dwAdd |= FWL_STYLEEXT_EDT_HFar;
496 break;
497 }
498 default: { dwAdd |= FWL_STYLEEXT_EDT_HNear; }
499 }
500 switch (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_CMB_EditVAlignMask) {
501 case FWL_STYLEEXT_CMB_EditVCenter: {
502 dwAdd |= FWL_STYLEEXT_EDT_VCenter;
503 break;
504 }
505 case FWL_STYLEEXT_CMB_EditVFar: {
506 dwAdd |= FWL_STYLEEXT_EDT_VFar;
507 break;
508 }
509 default: {
510 dwAdd |= FWL_STYLEEXT_EDT_VNear;
511 break;
512 }
513 }
514 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_CMB_EditJustified)
515 dwAdd |= FWL_STYLEEXT_EDT_Justified;
516 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_CMB_EditDistributed)
517 dwAdd |= FWL_STYLEEXT_EDT_Distributed;
518
519 m_pEdit->ModifyStylesEx(dwAdd, FWL_STYLEEXT_EDT_HAlignMask |
520 FWL_STYLEEXT_EDT_HAlignModeMask |
521 FWL_STYLEEXT_EDT_VAlignMask);
522 }
523
524 void IFWL_ComboBox::ResetListItemAlignment() {
525 if (!m_pListBox)
526 return;
527
528 uint32_t dwAdd = 0;
529 switch (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_CMB_ListItemAlignMask) {
530 case FWL_STYLEEXT_CMB_ListItemCenterAlign: {
531 dwAdd |= FWL_STYLEEXT_LTB_CenterAlign;
532 break;
533 }
534 case FWL_STYLEEXT_CMB_ListItemRightAlign: {
535 dwAdd |= FWL_STYLEEXT_LTB_RightAlign;
536 break;
537 }
538 default: {
539 dwAdd |= FWL_STYLEEXT_LTB_LeftAlign;
540 break;
541 }
542 }
543 m_pListBox->ModifyStylesEx(dwAdd, FWL_STYLEEXT_CMB_ListItemAlignMask);
544 }
545
546 void IFWL_ComboBox::ProcessSelChanged(bool bLButtonUp) {
547 m_iCurSel = m_pListBox->GetItemIndex(this, m_pListBox->GetSelItem(0));
548 if (!IsDropDownStyle()) {
549 Repaint(&m_rtClient);
550 return;
551 }
552
553 CFWL_ListItem* hItem = m_pListBox->GetItem(this, m_iCurSel);
554 if (!hItem)
555 return;
556
557 CFX_WideString wsText;
558 m_pListBox->GetItemText(this, hItem, wsText);
559 if (m_pEdit) {
560 m_pEdit->SetText(wsText);
561 m_pEdit->Update();
562 m_pEdit->SetSelected();
563 }
564
565 CFWL_EvtSelectChanged ev;
566 ev.bLButtonUp = bLButtonUp;
567 ev.m_pSrcTarget = this;
568 DispatchEvent(&ev);
569 }
570
571 void IFWL_ComboBox::InitProxyForm() {
572 if (m_pComboBoxProxy)
573 return;
574 if (!m_pListBox)
575 return;
576
577 auto prop = pdfium::MakeUnique<CFWL_WidgetProperties>();
578 prop->m_pOwner = this;
579 prop->m_dwStyles = FWL_WGTSTYLE_Popup;
580 prop->m_dwStates = FWL_WGTSTATE_Invisible;
581
582 // TODO(dsinclair): Does this leak? I don't see a delete, but I'm not sure
583 // if the SetParent call is going to transfer ownership.
584 m_pComboBoxProxy = new CFWL_ComboBoxProxy(this, m_pOwnerApp, std::move(prop),
585 m_pListBox.get());
586 m_pListBox->SetParent(m_pComboBoxProxy);
587 }
588
589 void IFWL_ComboBox::DisForm_InitComboList() {
590 if (m_pListBox)
591 return;
592
593 auto prop = pdfium::MakeUnique<CFWL_WidgetProperties>();
594 prop->m_pParent = this;
595 prop->m_dwStyles = FWL_WGTSTYLE_Border | FWL_WGTSTYLE_VScroll;
596 prop->m_dwStates = FWL_WGTSTATE_Invisible;
597 prop->m_pThemeProvider = m_pProperties->m_pThemeProvider;
598 m_pListBox =
599 pdfium::MakeUnique<CFWL_ComboList>(m_pOwnerApp, std::move(prop), this);
600 }
601
602 void IFWL_ComboBox::DisForm_InitComboEdit() {
603 if (m_pEdit)
604 return;
605
606 auto prop = pdfium::MakeUnique<CFWL_WidgetProperties>();
607 prop->m_pParent = this;
608 prop->m_pThemeProvider = m_pProperties->m_pThemeProvider;
609
610 m_pEdit =
611 pdfium::MakeUnique<CFWL_ComboEdit>(m_pOwnerApp, std::move(prop), this);
612 m_pEdit->SetOuter(this);
613 }
614
615 void IFWL_ComboBox::DisForm_ShowDropList(bool bActivate) {
616 if (DisForm_IsDropListVisible() == bActivate)
617 return;
618
619 if (bActivate) {
620 CFWL_EvtPreDropDown preEvent;
621 preEvent.m_pSrcTarget = this;
622 DispatchEvent(&preEvent);
623
624 CFWL_ComboList* pComboList = m_pListBox.get();
625 int32_t iItems = pComboList->CountItems(nullptr);
626 if (iItems < 1)
627 return;
628
629 ResetListItemAlignment();
630 pComboList->ChangeSelected(m_iCurSel);
631
632 FX_FLOAT fItemHeight = pComboList->CalcItemHeight();
633 FX_FLOAT fBorder = GetBorderSize();
634 FX_FLOAT fPopupMin = 0.0f;
635 if (iItems > 3)
636 fPopupMin = fItemHeight * 3 + fBorder * 2;
637
638 FX_FLOAT fPopupMax = fItemHeight * iItems + fBorder * 2;
639 CFX_RectF rtList;
640 rtList.left = m_rtClient.left;
641 rtList.width = m_pProperties->m_rtWidget.width;
642 rtList.top = 0;
643 rtList.height = 0;
644 GetPopupPos(fPopupMin, fPopupMax, m_pProperties->m_rtWidget, rtList);
645
646 m_pListBox->SetWidgetRect(rtList);
647 m_pListBox->Update();
648 } else {
649 SetFocus(true);
650 }
651
652 m_pListBox->SetStates(FWL_WGTSTATE_Invisible, !bActivate);
653 if (bActivate) {
654 CFWL_EvtPostDropDown postEvent;
655 postEvent.m_pSrcTarget = this;
656 DispatchEvent(&postEvent);
657 }
658
659 CFX_RectF rect;
660 m_pListBox->GetWidgetRect(rect);
661 rect.Inflate(2, 2);
662 Repaint(&rect);
663 }
664
665 void IFWL_ComboBox::DisForm_ModifyStylesEx(uint32_t dwStylesExAdded,
666 uint32_t dwStylesExRemoved) {
667 if (!m_pEdit)
668 DisForm_InitComboEdit();
669
670 bool bAddDropDown = !!(dwStylesExAdded & FWL_STYLEEXT_CMB_DropDown);
671 bool bDelDropDown = !!(dwStylesExRemoved & FWL_STYLEEXT_CMB_DropDown);
672
673 dwStylesExRemoved &= ~FWL_STYLEEXT_CMB_DropDown;
674 m_pProperties->m_dwStyleExes |= FWL_STYLEEXT_CMB_DropDown;
675
676 if (bAddDropDown)
677 m_pEdit->ModifyStylesEx(0, FWL_STYLEEXT_EDT_ReadOnly);
678 else if (bDelDropDown)
679 m_pEdit->ModifyStylesEx(FWL_STYLEEXT_EDT_ReadOnly, 0);
680 IFWL_Widget::ModifyStylesEx(dwStylesExAdded, dwStylesExRemoved);
681 }
682
683 void IFWL_ComboBox::DisForm_Update() {
684 if (m_iLock)
685 return;
686 if (m_pEdit)
687 ResetEditAlignment();
688 ResetTheme();
689 Layout();
690 }
691
692 FWL_WidgetHit IFWL_ComboBox::DisForm_HitTest(FX_FLOAT fx, FX_FLOAT fy) {
693 CFX_RectF rect;
694 rect.Set(0, 0, m_pProperties->m_rtWidget.width - m_rtBtn.width,
695 m_pProperties->m_rtWidget.height);
696 if (rect.Contains(fx, fy))
697 return FWL_WidgetHit::Edit;
698 if (m_rtBtn.Contains(fx, fy))
699 return FWL_WidgetHit::Client;
700 if (DisForm_IsDropListVisible()) {
701 m_pListBox->GetWidgetRect(rect);
702 if (rect.Contains(fx, fy))
703 return FWL_WidgetHit::Client;
704 }
705 return FWL_WidgetHit::Unknown;
706 }
707
708 void IFWL_ComboBox::DisForm_DrawWidget(CFX_Graphics* pGraphics,
709 const CFX_Matrix* pMatrix) {
710 IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
711 CFX_Matrix mtOrg;
712 mtOrg.Set(1, 0, 0, 1, 0, 0);
713 if (pMatrix)
714 mtOrg = *pMatrix;
715
716 pGraphics->SaveGraphState();
717 pGraphics->ConcatMatrix(&mtOrg);
718 if (!m_rtBtn.IsEmpty(0.1f)) {
719 CFWL_ThemeBackground param;
720 param.m_pWidget = this;
721 param.m_iPart = CFWL_Part::DropDownButton;
722 param.m_dwStates = m_iBtnState;
723 param.m_pGraphics = pGraphics;
724 param.m_rtPart = m_rtBtn;
725 pTheme->DrawBackground(&param);
726 }
727 pGraphics->RestoreGraphState();
728
729 if (m_pEdit) {
730 CFX_RectF rtEdit;
731 m_pEdit->GetWidgetRect(rtEdit);
732 CFX_Matrix mt;
733 mt.Set(1, 0, 0, 1, rtEdit.left, rtEdit.top);
734 mt.Concat(mtOrg);
735 m_pEdit->DrawWidget(pGraphics, &mt);
736 }
737 if (m_pListBox && DisForm_IsDropListVisible()) {
738 CFX_RectF rtList;
739 m_pListBox->GetWidgetRect(rtList);
740 CFX_Matrix mt;
741 mt.Set(1, 0, 0, 1, rtList.left, rtList.top);
742 mt.Concat(mtOrg);
743 m_pListBox->DrawWidget(pGraphics, &mt);
744 }
745 }
746
747 void IFWL_ComboBox::DisForm_GetBBox(CFX_RectF& rect) const {
748 rect = m_pProperties->m_rtWidget;
749 if (!m_pListBox || !DisForm_IsDropListVisible())
750 return;
751
752 CFX_RectF rtList;
753 m_pListBox->GetWidgetRect(rtList);
754 rtList.Offset(rect.left, rect.top);
755 rect.Union(rtList);
756 }
757
758 void IFWL_ComboBox::DisForm_Layout() {
759 GetClientRect(m_rtClient);
760 m_rtContent = m_rtClient;
761 FX_FLOAT* pFWidth = static_cast<FX_FLOAT*>(
762 GetThemeCapacity(CFWL_WidgetCapacity::ScrollBarWidth));
763 if (!pFWidth)
764 return;
765
766 FX_FLOAT borderWidth = 1;
767 FX_FLOAT fBtn = *pFWidth;
768 if (!(GetStylesEx() & FWL_STYLEEXT_CMB_ReadOnly)) {
769 m_rtBtn.Set(m_rtClient.right() - fBtn, m_rtClient.top + borderWidth,
770 fBtn - borderWidth, m_rtClient.height - 2 * borderWidth);
771 }
772
773 CFX_RectF* pUIMargin =
774 static_cast<CFX_RectF*>(GetThemeCapacity(CFWL_WidgetCapacity::UIMargin));
775 if (pUIMargin) {
776 m_rtContent.Deflate(pUIMargin->left, pUIMargin->top, pUIMargin->width,
777 pUIMargin->height);
778 }
779
780 if (!IsDropDownStyle() || !m_pEdit)
781 return;
782
783 CFX_RectF rtEdit;
784 rtEdit.Set(m_rtContent.left, m_rtContent.top, m_rtContent.width - fBtn,
785 m_rtContent.height);
786 m_pEdit->SetWidgetRect(rtEdit);
787
788 if (m_iCurSel >= 0) {
789 CFX_WideString wsText;
790 CFWL_ListItem* hItem = m_pListBox->GetItem(this, m_iCurSel);
791 m_pListBox->GetDataProviderItemText(hItem, wsText);
792 m_pEdit->LockUpdate();
793 m_pEdit->SetText(wsText);
794 m_pEdit->UnlockUpdate();
795 }
796 m_pEdit->Update();
797 }
798
799 void IFWL_ComboBox::OnProcessMessage(CFWL_Message* pMessage) {
800 if (m_pWidgetMgr->IsFormDisabled()) {
801 DisForm_OnProcessMessage(pMessage);
802 return;
803 }
804 if (!pMessage)
805 return;
806
807 switch (pMessage->GetClassID()) {
808 case CFWL_MessageType::SetFocus:
809 OnFocusChanged(pMessage, true);
810 break;
811 case CFWL_MessageType::KillFocus:
812 OnFocusChanged(pMessage, false);
813 break;
814 case CFWL_MessageType::Mouse: {
815 CFWL_MsgMouse* pMsg = static_cast<CFWL_MsgMouse*>(pMessage);
816 switch (pMsg->m_dwCmd) {
817 case FWL_MouseCommand::LeftButtonDown:
818 OnLButtonDown(pMsg);
819 break;
820 case FWL_MouseCommand::LeftButtonUp:
821 OnLButtonUp(pMsg);
822 break;
823 case FWL_MouseCommand::Move:
824 OnMouseMove(pMsg);
825 break;
826 case FWL_MouseCommand::Leave:
827 OnMouseLeave(pMsg);
828 break;
829 default:
830 break;
831 }
832 break;
833 }
834 case CFWL_MessageType::Key:
835 OnKey(static_cast<CFWL_MsgKey*>(pMessage));
836 break;
837 default:
838 break;
839 }
840
841 IFWL_Widget::OnProcessMessage(pMessage);
842 }
843
844 void IFWL_ComboBox::OnProcessEvent(CFWL_Event* pEvent) {
845 CFWL_EventType dwFlag = pEvent->GetClassID();
846 if (dwFlag == CFWL_EventType::Scroll) {
847 CFWL_EvtScroll* pScrollEvent = static_cast<CFWL_EvtScroll*>(pEvent);
848 CFWL_EvtScroll pScrollEv;
849 pScrollEv.m_pSrcTarget = this;
850 pScrollEv.m_iScrollCode = pScrollEvent->m_iScrollCode;
851 pScrollEv.m_fPos = pScrollEvent->m_fPos;
852 DispatchEvent(&pScrollEv);
853 } else if (dwFlag == CFWL_EventType::TextChanged) {
854 CFWL_EvtEditChanged pTemp;
855 pTemp.m_pSrcTarget = this;
856 DispatchEvent(&pTemp);
857 }
858 }
859
860 void IFWL_ComboBox::OnDrawWidget(CFX_Graphics* pGraphics,
861 const CFX_Matrix* pMatrix) {
862 DrawWidget(pGraphics, pMatrix);
863 }
864
865 void IFWL_ComboBox::OnFocusChanged(CFWL_Message* pMsg, bool bSet) {
866 if (bSet) {
867 m_pProperties->m_dwStates |= FWL_WGTSTATE_Focused;
868 if (IsDropDownStyle() && pMsg->m_pSrcTarget != m_pListBox.get()) {
869 if (!m_pEdit)
870 return;
871 m_pEdit->SetSelected();
872 return;
873 }
874
875 Repaint(&m_rtClient);
876 return;
877 }
878
879 m_pProperties->m_dwStates &= ~FWL_WGTSTATE_Focused;
880 if (!IsDropDownStyle() || pMsg->m_pDstTarget == m_pListBox.get()) {
881 Repaint(&m_rtClient);
882 return;
883 }
884 if (!m_pEdit)
885 return;
886
887 m_pEdit->FlagFocus(false);
888 m_pEdit->ClearSelected();
889 }
890
891 void IFWL_ComboBox::OnLButtonDown(CFWL_MsgMouse* pMsg) {
892 if (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled)
893 return;
894
895 CFX_RectF& rtBtn = IsDropDownStyle() ? m_rtBtn : m_rtClient;
896 if (!rtBtn.Contains(pMsg->m_fx, pMsg->m_fy))
897 return;
898
899 if (IsDropDownStyle() && m_pEdit)
900 MatchEditText();
901
902 m_bLButtonDown = true;
903 m_iBtnState = CFWL_PartState_Pressed;
904 Repaint(&m_rtClient);
905
906 ShowDropList(true);
907 m_iBtnState = CFWL_PartState_Normal;
908 Repaint(&m_rtClient);
909 }
910
911 void IFWL_ComboBox::OnLButtonUp(CFWL_MsgMouse* pMsg) {
912 m_bLButtonDown = false;
913 if (m_rtBtn.Contains(pMsg->m_fx, pMsg->m_fy))
914 m_iBtnState = CFWL_PartState_Hovered;
915 else
916 m_iBtnState = CFWL_PartState_Normal;
917
918 Repaint(&m_rtBtn);
919 }
920
921 void IFWL_ComboBox::OnMouseMove(CFWL_MsgMouse* pMsg) {
922 int32_t iOldState = m_iBtnState;
923 if (m_rtBtn.Contains(pMsg->m_fx, pMsg->m_fy)) {
924 m_iBtnState =
925 m_bLButtonDown ? CFWL_PartState_Pressed : CFWL_PartState_Hovered;
926 } else {
927 m_iBtnState = CFWL_PartState_Normal;
928 }
929 if ((iOldState != m_iBtnState) &&
930 !((m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled) ==
931 FWL_WGTSTATE_Disabled)) {
932 Repaint(&m_rtBtn);
933 }
934 }
935
936 void IFWL_ComboBox::OnMouseLeave(CFWL_MsgMouse* pMsg) {
937 if (!IsDropListVisible() &&
938 !((m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled) ==
939 FWL_WGTSTATE_Disabled)) {
940 m_iBtnState = CFWL_PartState_Normal;
941 Repaint(&m_rtBtn);
942 }
943 }
944
945 void IFWL_ComboBox::OnKey(CFWL_MsgKey* pMsg) {
946 uint32_t dwKeyCode = pMsg->m_dwKeyCode;
947 if (dwKeyCode == FWL_VKEY_Tab) {
948 DispatchKeyEvent(pMsg);
949 return;
950 }
951 if (pMsg->m_pDstTarget == this)
952 DoSubCtrlKey(pMsg);
953 }
954
955 void IFWL_ComboBox::DoSubCtrlKey(CFWL_MsgKey* pMsg) {
956 uint32_t dwKeyCode = pMsg->m_dwKeyCode;
957 const bool bUp = dwKeyCode == FWL_VKEY_Up;
958 const bool bDown = dwKeyCode == FWL_VKEY_Down;
959 if (bUp || bDown) {
960 int32_t iCount = m_pListBox->CountItems(nullptr);
961 if (iCount < 1)
962 return;
963
964 bool bMatchEqual = false;
965 int32_t iCurSel = m_iCurSel;
966 bool bDropDown = IsDropDownStyle();
967 if (bDropDown && m_pEdit) {
968 CFX_WideString wsText;
969 m_pEdit->GetText(wsText);
970 iCurSel = m_pListBox->MatchItem(wsText);
971 if (iCurSel >= 0) {
972 CFX_WideString wsTemp;
973 CFWL_ListItem* hItem = m_pListBox->GetItem(this, iCurSel);
974 m_pListBox->GetDataProviderItemText(hItem, wsTemp);
975 bMatchEqual = wsText == wsTemp;
976 }
977 }
978 if (iCurSel < 0) {
979 iCurSel = 0;
980 } else if (!bDropDown || bMatchEqual) {
981 if ((bUp && iCurSel == 0) || (bDown && iCurSel == iCount - 1))
982 return;
983 if (bUp)
984 iCurSel--;
985 else
986 iCurSel++;
987 }
988 m_iCurSel = iCurSel;
989 if (bDropDown && m_pEdit)
990 SyncEditText(m_iCurSel);
991 else
992 Repaint(&m_rtClient);
993 return;
994 }
995
996 if (IsDropDownStyle())
997 m_pEdit->GetDelegate()->OnProcessMessage(pMsg);
998 }
999
1000 void IFWL_ComboBox::DisForm_OnProcessMessage(CFWL_Message* pMessage) {
1001 if (!pMessage)
1002 return;
1003
1004 bool backDefault = true;
1005 switch (pMessage->GetClassID()) {
1006 case CFWL_MessageType::SetFocus: {
1007 backDefault = false;
1008 DisForm_OnFocusChanged(pMessage, true);
1009 break;
1010 }
1011 case CFWL_MessageType::KillFocus: {
1012 backDefault = false;
1013 DisForm_OnFocusChanged(pMessage, false);
1014 break;
1015 }
1016 case CFWL_MessageType::Mouse: {
1017 backDefault = false;
1018 CFWL_MsgMouse* pMsg = static_cast<CFWL_MsgMouse*>(pMessage);
1019 switch (pMsg->m_dwCmd) {
1020 case FWL_MouseCommand::LeftButtonDown:
1021 DisForm_OnLButtonDown(pMsg);
1022 break;
1023 case FWL_MouseCommand::LeftButtonUp:
1024 OnLButtonUp(pMsg);
1025 break;
1026 default:
1027 break;
1028 }
1029 break;
1030 }
1031 case CFWL_MessageType::Key: {
1032 backDefault = false;
1033 CFWL_MsgKey* pKey = static_cast<CFWL_MsgKey*>(pMessage);
1034 if (pKey->m_dwCmd == FWL_KeyCommand::KeyUp)
1035 break;
1036 if (DisForm_IsDropListVisible() &&
1037 pKey->m_dwCmd == FWL_KeyCommand::KeyDown) {
1038 bool bListKey = pKey->m_dwKeyCode == FWL_VKEY_Up ||
1039 pKey->m_dwKeyCode == FWL_VKEY_Down ||
1040 pKey->m_dwKeyCode == FWL_VKEY_Return ||
1041 pKey->m_dwKeyCode == FWL_VKEY_Escape;
1042 if (bListKey) {
1043 m_pListBox->GetDelegate()->OnProcessMessage(pMessage);
1044 break;
1045 }
1046 }
1047 DisForm_OnKey(pKey);
1048 break;
1049 }
1050 default:
1051 break;
1052 }
1053 if (backDefault)
1054 IFWL_Widget::OnProcessMessage(pMessage);
1055 }
1056
1057 void IFWL_ComboBox::DisForm_OnLButtonDown(CFWL_MsgMouse* pMsg) {
1058 bool bDropDown = DisForm_IsDropListVisible();
1059 CFX_RectF& rtBtn = bDropDown ? m_rtBtn : m_rtClient;
1060 if (!rtBtn.Contains(pMsg->m_fx, pMsg->m_fy))
1061 return;
1062
1063 if (DisForm_IsDropListVisible()) {
1064 DisForm_ShowDropList(false);
1065 return;
1066 }
1067 if (m_pEdit)
1068 MatchEditText();
1069 DisForm_ShowDropList(true);
1070 }
1071
1072 void IFWL_ComboBox::DisForm_OnFocusChanged(CFWL_Message* pMsg, bool bSet) {
1073 if (bSet) {
1074 m_pProperties->m_dwStates |= FWL_WGTSTATE_Focused;
1075 if ((m_pEdit->GetStates() & FWL_WGTSTATE_Focused) == 0) {
1076 CFWL_MsgSetFocus msg;
1077 msg.m_pDstTarget = m_pEdit.get();
1078 msg.m_pSrcTarget = nullptr;
1079 m_pEdit->GetDelegate()->OnProcessMessage(&msg);
1080 }
1081 } else {
1082 m_pProperties->m_dwStates &= ~FWL_WGTSTATE_Focused;
1083 DisForm_ShowDropList(false);
1084 CFWL_MsgKillFocus msg;
1085 msg.m_pDstTarget = nullptr;
1086 msg.m_pSrcTarget = m_pEdit.get();
1087 m_pEdit->GetDelegate()->OnProcessMessage(&msg);
1088 }
1089 }
1090
1091 void IFWL_ComboBox::DisForm_OnKey(CFWL_MsgKey* pMsg) {
1092 uint32_t dwKeyCode = pMsg->m_dwKeyCode;
1093 const bool bUp = dwKeyCode == FWL_VKEY_Up;
1094 const bool bDown = dwKeyCode == FWL_VKEY_Down;
1095 if (bUp || bDown) {
1096 CFWL_ComboList* pComboList = m_pListBox.get();
1097 int32_t iCount = pComboList->CountItems(nullptr);
1098 if (iCount < 1)
1099 return;
1100
1101 bool bMatchEqual = false;
1102 int32_t iCurSel = m_iCurSel;
1103 if (m_pEdit) {
1104 CFX_WideString wsText;
1105 m_pEdit->GetText(wsText);
1106 iCurSel = pComboList->MatchItem(wsText);
1107 if (iCurSel >= 0) {
1108 CFX_WideString wsTemp;
1109 CFWL_ListItem* item = m_pListBox->GetSelItem(iCurSel);
1110 m_pListBox->GetDataProviderItemText(item, wsTemp);
1111 bMatchEqual = wsText == wsTemp;
1112 }
1113 }
1114 if (iCurSel < 0) {
1115 iCurSel = 0;
1116 } else if (bMatchEqual) {
1117 if ((bUp && iCurSel == 0) || (bDown && iCurSel == iCount - 1))
1118 return;
1119 if (bUp)
1120 iCurSel--;
1121 else
1122 iCurSel++;
1123 }
1124 m_iCurSel = iCurSel;
1125 SyncEditText(m_iCurSel);
1126 return;
1127 }
1128 if (m_pEdit)
1129 m_pEdit->GetDelegate()->OnProcessMessage(pMsg);
1130 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698