• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "xfa/fwl/cfwl_datetimepicker.h"
8 
9 #include "xfa/fwl/cfwl_app.h"
10 #include "xfa/fwl/cfwl_event.h"
11 #include "xfa/fwl/cfwl_eventselectchanged.h"
12 #include "xfa/fwl/cfwl_messagemouse.h"
13 #include "xfa/fwl/cfwl_messagesetfocus.h"
14 #include "xfa/fwl/cfwl_notedriver.h"
15 #include "xfa/fwl/cfwl_themebackground.h"
16 #include "xfa/fwl/cfwl_widgetmgr.h"
17 #include "xfa/fwl/ifwl_themeprovider.h"
18 
19 namespace pdfium {
20 
21 namespace {
22 
23 constexpr int kDateTimePickerHeight = 20;
24 
25 }  // namespace
26 
CFWL_DateTimePicker(CFWL_App * app)27 CFWL_DateTimePicker::CFWL_DateTimePicker(CFWL_App* app)
28     : CFWL_Widget(app,
29                   Properties{0, FWL_STYLEEXT_DTP_ShortDateFormat, 0},
30                   nullptr),
31       m_pEdit(cppgc::MakeGarbageCollected<CFWL_DateTimeEdit>(
32           app->GetHeap()->GetAllocationHandle(),
33           app,
34           Properties(),
35           this)),
36       m_pMonthCal(cppgc::MakeGarbageCollected<CFWL_MonthCalendar>(
37           app->GetHeap()->GetAllocationHandle(),
38           app,
39           Properties{FWL_STYLE_WGT_Popup | FWL_STYLE_WGT_Border, 0,
40                      FWL_STATE_WGT_Invisible},
41           this)) {
42   m_pMonthCal->SetWidgetRect(
43       CFX_RectF(0, 0, m_pMonthCal->GetAutosizedWidgetRect().Size()));
44 
45   CFWL_NoteDriver* pNoteDriver = GetFWLApp()->GetNoteDriver();
46   pNoteDriver->RegisterEventTarget(this, m_pMonthCal);
47   pNoteDriver->RegisterEventTarget(this, m_pEdit);
48 }
49 
50 CFWL_DateTimePicker::~CFWL_DateTimePicker() = default;
51 
PreFinalize()52 void CFWL_DateTimePicker::PreFinalize() {
53   UnregisterEventTarget();
54   CFWL_Widget::PreFinalize();
55 }
56 
Trace(cppgc::Visitor * visitor) const57 void CFWL_DateTimePicker::Trace(cppgc::Visitor* visitor) const {
58   CFWL_Widget::Trace(visitor);
59   visitor->Trace(m_pEdit);
60   visitor->Trace(m_pMonthCal);
61 }
62 
GetClassID() const63 FWL_Type CFWL_DateTimePicker::GetClassID() const {
64   return FWL_Type::DateTimePicker;
65 }
66 
Update()67 void CFWL_DateTimePicker::Update() {
68   if (IsLocked())
69     return;
70 
71   m_ClientRect = GetClientRect();
72   m_pEdit->SetWidgetRect(m_ClientRect);
73   ResetEditAlignment();
74   m_pEdit->Update();
75 
76   m_fBtn = GetThemeProvider()->GetScrollBarWidth();
77   CFX_RectF rtMonthCal = m_pMonthCal->GetAutosizedWidgetRect();
78   CFX_RectF rtPopUp(rtMonthCal.left, rtMonthCal.top + kDateTimePickerHeight,
79                     rtMonthCal.width, rtMonthCal.height);
80   m_pMonthCal->SetWidgetRect(rtPopUp);
81   m_pMonthCal->Update();
82 }
83 
HitTest(const CFX_PointF & point)84 FWL_WidgetHit CFWL_DateTimePicker::HitTest(const CFX_PointF& point) {
85   CFX_RectF rect(0, 0, m_WidgetRect.width, m_WidgetRect.height);
86   if (rect.Contains(point))
87     return FWL_WidgetHit::Edit;
88   if (NeedsToShowButton())
89     rect.width += m_fBtn;
90   if (rect.Contains(point))
91     return FWL_WidgetHit::Client;
92   if (IsMonthCalendarVisible()) {
93     if (m_pMonthCal->GetWidgetRect().Contains(point))
94       return FWL_WidgetHit::Client;
95   }
96   return FWL_WidgetHit::Unknown;
97 }
98 
DrawWidget(CFGAS_GEGraphics * pGraphics,const CFX_Matrix & matrix)99 void CFWL_DateTimePicker::DrawWidget(CFGAS_GEGraphics* pGraphics,
100                                      const CFX_Matrix& matrix) {
101   if (!pGraphics)
102     return;
103 
104   if (HasBorder())
105     DrawBorder(pGraphics, CFWL_ThemePart::Part::kBorder, matrix);
106 
107   if (!m_BtnRect.IsEmpty())
108     DrawDropDownButton(pGraphics, matrix);
109 
110   if (m_pEdit) {
111     CFX_RectF rtEdit = m_pEdit->GetWidgetRect();
112     CFX_Matrix mt(1, 0, 0, 1, rtEdit.left, rtEdit.top);
113     mt.Concat(matrix);
114     m_pEdit->DrawWidget(pGraphics, mt);
115   }
116   if (!IsMonthCalendarVisible())
117     return;
118 
119   CFX_RectF rtMonth = m_pMonthCal->GetWidgetRect();
120   CFX_Matrix mt(1, 0, 0, 1, rtMonth.left, rtMonth.top);
121   mt.Concat(matrix);
122   m_pMonthCal->DrawWidget(pGraphics, mt);
123 }
124 
GetCurSel(int32_t & iYear,int32_t & iMonth,int32_t & iDay)125 void CFWL_DateTimePicker::GetCurSel(int32_t& iYear,
126                                     int32_t& iMonth,
127                                     int32_t& iDay) {
128   iYear = m_iYear;
129   iMonth = m_iMonth;
130   iDay = m_iDay;
131 }
132 
SetCurSel(int32_t iYear,int32_t iMonth,int32_t iDay)133 void CFWL_DateTimePicker::SetCurSel(int32_t iYear,
134                                     int32_t iMonth,
135                                     int32_t iDay) {
136   if (iYear <= 0 || iYear >= 3000)
137     return;
138   if (iMonth <= 0 || iMonth >= 13)
139     return;
140   if (iDay <= 0 || iDay >= 32)
141     return;
142 
143   m_iYear = iYear;
144   m_iMonth = iMonth;
145   m_iDay = iDay;
146   m_pMonthCal->SetSelect(iYear, iMonth, iDay);
147 }
148 
SetEditText(const WideString & wsText)149 void CFWL_DateTimePicker::SetEditText(const WideString& wsText) {
150   if (!m_pEdit)
151     return;
152 
153   m_pEdit->SetText(wsText);
154   RepaintRect(m_ClientRect);
155 
156   CFWL_Event ev(CFWL_Event::Type::EditChanged);
157   DispatchEvent(&ev);
158 }
159 
GetEditText() const160 WideString CFWL_DateTimePicker::GetEditText() const {
161   return m_pEdit ? m_pEdit->GetText() : WideString();
162 }
163 
GetEditTextLength() const164 size_t CFWL_DateTimePicker::GetEditTextLength() const {
165   return m_pEdit ? m_pEdit->GetTextLength() : 0;
166 }
167 
GetBBox() const168 CFX_RectF CFWL_DateTimePicker::GetBBox() const {
169   CFX_RectF rect = m_WidgetRect;
170   if (NeedsToShowButton())
171     rect.width += m_fBtn;
172   if (!IsMonthCalendarVisible())
173     return rect;
174 
175   CFX_RectF rtMonth = m_pMonthCal->GetWidgetRect();
176   rtMonth.Offset(m_WidgetRect.left, m_WidgetRect.top);
177   rect.Union(rtMonth);
178   return rect;
179 }
180 
ModifyEditStyleExts(uint32_t dwStyleExtsAdded,uint32_t dwStyleExtsRemoved)181 void CFWL_DateTimePicker::ModifyEditStyleExts(uint32_t dwStyleExtsAdded,
182                                               uint32_t dwStyleExtsRemoved) {
183   m_pEdit->ModifyStyleExts(dwStyleExtsAdded, dwStyleExtsRemoved);
184 }
185 
DrawDropDownButton(CFGAS_GEGraphics * pGraphics,const CFX_Matrix & mtMatrix)186 void CFWL_DateTimePicker::DrawDropDownButton(CFGAS_GEGraphics* pGraphics,
187                                              const CFX_Matrix& mtMatrix) {
188   CFWL_ThemeBackground param(CFWL_ThemePart::Part::kDropDownButton, this,
189                              pGraphics);
190   param.m_dwStates = m_iBtnState;
191   param.m_PartRect = m_BtnRect;
192   param.m_matrix = mtMatrix;
193   GetThemeProvider()->DrawBackground(param);
194 }
195 
FormatDateString(int32_t iYear,int32_t iMonth,int32_t iDay)196 WideString CFWL_DateTimePicker::FormatDateString(int32_t iYear,
197                                                  int32_t iMonth,
198                                                  int32_t iDay) {
199   if (m_Properties.m_dwStyleExts & FWL_STYLEEXT_DTP_ShortDateFormat)
200     return WideString::Format(L"%d-%d-%d", iYear, iMonth, iDay);
201 
202   return WideString::Format(L"%d Year %d Month %d Day", iYear, iMonth, iDay);
203 }
204 
ShowMonthCalendar()205 void CFWL_DateTimePicker::ShowMonthCalendar() {
206   if (IsMonthCalendarVisible())
207     return;
208 
209   CFX_RectF rtMonthCal = m_pMonthCal->GetAutosizedWidgetRect();
210   float fPopupMin = rtMonthCal.height;
211   float fPopupMax = rtMonthCal.height;
212   CFX_RectF rtAnchor = m_WidgetRect;
213   rtAnchor.width = rtMonthCal.width;
214   rtMonthCal.left = m_ClientRect.left;
215   rtMonthCal.top = rtAnchor.Height();
216   GetPopupPos(fPopupMin, fPopupMax, rtAnchor, &rtMonthCal);
217   m_pMonthCal->SetWidgetRect(rtMonthCal);
218   if (m_iYear > 0 && m_iMonth > 0 && m_iDay > 0)
219     m_pMonthCal->SetSelect(m_iYear, m_iMonth, m_iDay);
220   m_pMonthCal->Update();
221   m_pMonthCal->RemoveStates(FWL_STATE_WGT_Invisible);
222 
223   CFWL_MessageSetFocus msg(m_pMonthCal);
224   m_pEdit->GetDelegate()->OnProcessMessage(&msg);
225   RepaintInflatedMonthCalRect();
226 }
227 
HideMonthCalendar()228 void CFWL_DateTimePicker::HideMonthCalendar() {
229   if (!IsMonthCalendarVisible())
230     return;
231 
232   m_pMonthCal->SetStates(FWL_STATE_WGT_Invisible);
233   RepaintInflatedMonthCalRect();
234 }
235 
RepaintInflatedMonthCalRect()236 void CFWL_DateTimePicker::RepaintInflatedMonthCalRect() {
237   CFX_RectF rtInvalidate(0, 0, m_WidgetRect.width, m_WidgetRect.height);
238   CFX_RectF rtCal = m_pMonthCal->GetWidgetRect();
239   rtInvalidate.Union(rtCal);
240   rtInvalidate.Inflate(2, 2);
241   RepaintRect(rtInvalidate);
242 }
243 
IsMonthCalendarVisible() const244 bool CFWL_DateTimePicker::IsMonthCalendarVisible() const {
245   return m_pMonthCal && m_pMonthCal->IsVisible();
246 }
247 
ResetEditAlignment()248 void CFWL_DateTimePicker::ResetEditAlignment() {
249   if (!m_pEdit)
250     return;
251 
252   uint32_t dwAdd = 0;
253   switch (m_Properties.m_dwStyleExts & FWL_STYLEEXT_DTP_EditHAlignMask) {
254     case FWL_STYLEEXT_DTP_EditHCenter: {
255       dwAdd |= FWL_STYLEEXT_EDT_HCenter;
256       break;
257     }
258     case FWL_STYLEEXT_DTP_EditHFar: {
259       dwAdd |= FWL_STYLEEXT_EDT_HFar;
260       break;
261     }
262     default: {
263       dwAdd |= FWL_STYLEEXT_EDT_HNear;
264       break;
265     }
266   }
267   switch (m_Properties.m_dwStyleExts & FWL_STYLEEXT_DTP_EditVAlignMask) {
268     case FWL_STYLEEXT_DTP_EditVCenter: {
269       dwAdd |= FWL_STYLEEXT_EDT_VCenter;
270       break;
271     }
272     case FWL_STYLEEXT_DTP_EditVFar: {
273       dwAdd |= FWL_STYLEEXT_EDT_VFar;
274       break;
275     }
276     default: {
277       dwAdd |= FWL_STYLEEXT_EDT_VNear;
278       break;
279     }
280   }
281   if (m_Properties.m_dwStyleExts & FWL_STYLEEXT_DTP_EditJustified)
282     dwAdd |= FWL_STYLEEXT_EDT_Justified;
283 
284   m_pEdit->ModifyStyleExts(dwAdd, FWL_STYLEEXT_EDT_HAlignMask |
285                                       FWL_STYLEEXT_EDT_HAlignModeMask |
286                                       FWL_STYLEEXT_EDT_VAlignMask);
287 }
288 
ProcessSelChanged(int32_t iYear,int32_t iMonth,int32_t iDay)289 void CFWL_DateTimePicker::ProcessSelChanged(int32_t iYear,
290                                             int32_t iMonth,
291                                             int32_t iDay) {
292   m_iYear = iYear;
293   m_iMonth = iMonth;
294   m_iDay = iDay;
295   m_pEdit->SetText(FormatDateString(m_iYear, m_iMonth, m_iDay));
296   m_pEdit->Update();
297   RepaintRect(m_ClientRect);
298 
299   CFWL_EventSelectChanged ev(this, m_iYear, m_iMonth, m_iDay);
300   DispatchEvent(&ev);
301 }
302 
NeedsToShowButton() const303 bool CFWL_DateTimePicker::NeedsToShowButton() const {
304   return m_Properties.m_dwStates & FWL_STATE_WGT_Focused ||
305          m_pMonthCal->GetStates() & FWL_STATE_WGT_Focused ||
306          m_pEdit->GetStates() & FWL_STATE_WGT_Focused;
307 }
308 
OnProcessMessage(CFWL_Message * pMessage)309 void CFWL_DateTimePicker::OnProcessMessage(CFWL_Message* pMessage) {
310   switch (pMessage->GetType()) {
311     case CFWL_Message::Type::kSetFocus:
312       OnFocusGained(pMessage);
313       break;
314     case CFWL_Message::Type::kKillFocus:
315       OnFocusLost(pMessage);
316       break;
317     case CFWL_Message::Type::kMouse: {
318       CFWL_MessageMouse* pMouse = static_cast<CFWL_MessageMouse*>(pMessage);
319       switch (pMouse->m_dwCmd) {
320         case CFWL_MessageMouse::MouseCommand::kLeftButtonDown:
321           OnLButtonDown(pMouse);
322           break;
323         case CFWL_MessageMouse::MouseCommand::kLeftButtonUp:
324           OnLButtonUp(pMouse);
325           break;
326         case CFWL_MessageMouse::MouseCommand::kMove:
327           OnMouseMove(pMouse);
328           break;
329         case CFWL_MessageMouse::MouseCommand::kLeave:
330           OnMouseLeave(pMouse);
331           break;
332         default:
333           break;
334       }
335       break;
336     }
337     case CFWL_Message::Type::kKey: {
338       if (m_pEdit->GetStates() & FWL_STATE_WGT_Focused) {
339         m_pEdit->GetDelegate()->OnProcessMessage(pMessage);
340         return;
341       }
342       break;
343     }
344     default:
345       break;
346   }
347   // Dst target could be |this|, continue only if not destroyed by above.
348   if (pMessage->GetDstTarget())
349     CFWL_Widget::OnProcessMessage(pMessage);
350 }
351 
OnDrawWidget(CFGAS_GEGraphics * pGraphics,const CFX_Matrix & matrix)352 void CFWL_DateTimePicker::OnDrawWidget(CFGAS_GEGraphics* pGraphics,
353                                        const CFX_Matrix& matrix) {
354   DrawWidget(pGraphics, matrix);
355 }
356 
OnFocusGained(CFWL_Message * pMsg)357 void CFWL_DateTimePicker::OnFocusGained(CFWL_Message* pMsg) {
358   m_Properties.m_dwStates |= FWL_STATE_WGT_Focused;
359   if (m_pEdit && !(m_pEdit->GetStyleExts() & FWL_STYLEEXT_EDT_ReadOnly)) {
360     m_BtnRect =
361         CFX_RectF(m_WidgetRect.width, 0, m_fBtn, m_WidgetRect.height - 1);
362   }
363   CFX_RectF rtInvalidate(m_BtnRect);
364   pMsg->SetDstTarget(m_pEdit);
365   m_pEdit->GetDelegate()->OnProcessMessage(pMsg);
366   rtInvalidate.Inflate(2, 2);
367   RepaintRect(rtInvalidate);
368 }
369 
OnFocusLost(CFWL_Message * pMsg)370 void CFWL_DateTimePicker::OnFocusLost(CFWL_Message* pMsg) {
371   CFX_RectF rtInvalidate(m_BtnRect);
372   m_Properties.m_dwStates &= ~FWL_STATE_WGT_Focused;
373   m_BtnRect = CFX_RectF();
374   HideMonthCalendar();
375   if (m_pEdit->GetStates() & FWL_STATE_WGT_Focused)
376     m_pEdit->GetDelegate()->OnProcessMessage(pMsg);
377   rtInvalidate.Inflate(2, 2);
378   RepaintRect(rtInvalidate);
379 }
380 
OnLButtonDown(CFWL_MessageMouse * pMsg)381 void CFWL_DateTimePicker::OnLButtonDown(CFWL_MessageMouse* pMsg) {
382   if (!pMsg)
383     return;
384   if (!m_BtnRect.Contains(pMsg->m_pos))
385     return;
386 
387   if (IsMonthCalendarVisible()) {
388     HideMonthCalendar();
389     return;
390   }
391   ShowMonthCalendar();
392   m_bLBtnDown = true;
393   RepaintRect(m_ClientRect);
394 }
395 
OnLButtonUp(CFWL_MessageMouse * pMsg)396 void CFWL_DateTimePicker::OnLButtonUp(CFWL_MessageMouse* pMsg) {
397   if (!pMsg)
398     return;
399 
400   m_bLBtnDown = false;
401   if (m_BtnRect.Contains(pMsg->m_pos))
402     m_iBtnState = CFWL_PartState::kHovered;
403   else
404     m_iBtnState = CFWL_PartState::kNormal;
405   RepaintRect(m_BtnRect);
406 }
407 
OnMouseMove(CFWL_MessageMouse * pMsg)408 void CFWL_DateTimePicker::OnMouseMove(CFWL_MessageMouse* pMsg) {
409   if (!m_BtnRect.Contains(pMsg->m_pos))
410     m_iBtnState = CFWL_PartState::kNormal;
411   RepaintRect(m_BtnRect);
412 }
413 
OnMouseLeave(CFWL_MessageMouse * pMsg)414 void CFWL_DateTimePicker::OnMouseLeave(CFWL_MessageMouse* pMsg) {
415   if (!pMsg)
416     return;
417   m_iBtnState = CFWL_PartState::kNormal;
418   RepaintRect(m_BtnRect);
419 }
420 
GetPopupPos(float fMinHeight,float fMaxHeight,const CFX_RectF & rtAnchor,CFX_RectF * pPopupRect)421 void CFWL_DateTimePicker::GetPopupPos(float fMinHeight,
422                                       float fMaxHeight,
423                                       const CFX_RectF& rtAnchor,
424                                       CFX_RectF* pPopupRect) {
425   GetWidgetMgr()->GetAdapterPopupPos(this, fMinHeight, fMaxHeight, rtAnchor,
426                                      pPopupRect);
427 }
428 
ClearText()429 void CFWL_DateTimePicker::ClearText() {
430   m_pEdit->ClearText();
431 }
432 
SelectAll()433 void CFWL_DateTimePicker::SelectAll() {
434   m_pEdit->SelectAll();
435 }
436 
ClearSelection()437 void CFWL_DateTimePicker::ClearSelection() {
438   m_pEdit->ClearSelection();
439 }
440 
Copy()441 std::optional<WideString> CFWL_DateTimePicker::Copy() {
442   return m_pEdit->Copy();
443 }
444 
Cut()445 std::optional<WideString> CFWL_DateTimePicker::Cut() {
446   return m_pEdit->Cut();
447 }
448 
Paste(const WideString & wsPaste)449 bool CFWL_DateTimePicker::Paste(const WideString& wsPaste) {
450   return m_pEdit->Paste(wsPaste);
451 }
452 
Undo()453 bool CFWL_DateTimePicker::Undo() {
454   return m_pEdit->Undo();
455 }
456 
Redo()457 bool CFWL_DateTimePicker::Redo() {
458   return m_pEdit->Redo();
459 }
460 
CanUndo()461 bool CFWL_DateTimePicker::CanUndo() {
462   return m_pEdit->CanUndo();
463 }
464 
CanRedo()465 bool CFWL_DateTimePicker::CanRedo() {
466   return m_pEdit->CanRedo();
467 }
468 
469 }  // namespace pdfium
470