• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/cfwl_checkbox.h"
8 
9 #include <algorithm>
10 #include <memory>
11 #include <utility>
12 #include <vector>
13 
14 #include "third_party/base/ptr_util.h"
15 #include "xfa/fde/tto/fde_textout.h"
16 #include "xfa/fwl/cfwl_app.h"
17 #include "xfa/fwl/cfwl_event.h"
18 #include "xfa/fwl/cfwl_messagekey.h"
19 #include "xfa/fwl/cfwl_messagemouse.h"
20 #include "xfa/fwl/cfwl_notedriver.h"
21 #include "xfa/fwl/cfwl_themebackground.h"
22 #include "xfa/fwl/cfwl_themetext.h"
23 #include "xfa/fwl/cfwl_widgetmgr.h"
24 #include "xfa/fwl/ifwl_themeprovider.h"
25 
26 namespace {
27 
28 const int kCaptionMargin = 5;
29 
30 }  // namespace
31 
CFWL_CheckBox(const CFWL_App * app)32 CFWL_CheckBox::CFWL_CheckBox(const CFWL_App* app)
33     : CFWL_Widget(app, pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr),
34       m_dwTTOStyles(FDE_TTOSTYLE_SingleLine),
35       m_iTTOAlign(FDE_TTOALIGNMENT_Center),
36       m_bBtnDown(false),
37       m_fBoxHeight(16.0f) {
38   m_rtClient.Reset();
39   m_rtBox.Reset();
40   m_rtCaption.Reset();
41   m_rtFocus.Reset();
42 }
43 
~CFWL_CheckBox()44 CFWL_CheckBox::~CFWL_CheckBox() {}
45 
GetClassID() const46 FWL_Type CFWL_CheckBox::GetClassID() const {
47   return FWL_Type::CheckBox;
48 }
49 
SetBoxSize(FX_FLOAT fHeight)50 void CFWL_CheckBox::SetBoxSize(FX_FLOAT fHeight) {
51   m_fBoxHeight = fHeight;
52 }
53 
Update()54 void CFWL_CheckBox::Update() {
55   if (IsLocked())
56     return;
57   if (!m_pProperties->m_pThemeProvider)
58     m_pProperties->m_pThemeProvider = GetAvailableTheme();
59 
60   UpdateTextOutStyles();
61   Layout();
62 }
63 
DrawWidget(CFX_Graphics * pGraphics,const CFX_Matrix * pMatrix)64 void CFWL_CheckBox::DrawWidget(CFX_Graphics* pGraphics,
65                                const CFX_Matrix* pMatrix) {
66   if (!pGraphics)
67     return;
68   if (!m_pProperties->m_pThemeProvider)
69     return;
70 
71   IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
72   if (HasBorder()) {
73     DrawBorder(pGraphics, CFWL_Part::Border, m_pProperties->m_pThemeProvider,
74                pMatrix);
75   }
76 
77   int32_t dwStates = GetPartStates();
78 
79   CFWL_ThemeBackground param;
80   param.m_pWidget = this;
81   param.m_iPart = CFWL_Part::Background;
82   param.m_dwStates = dwStates;
83   param.m_pGraphics = pGraphics;
84   if (pMatrix)
85     param.m_matrix.Concat(*pMatrix);
86   param.m_rtPart = m_rtClient;
87   if (m_pProperties->m_dwStates & FWL_WGTSTATE_Focused)
88     param.m_pData = &m_rtFocus;
89   pTheme->DrawBackground(&param);
90 
91   param.m_iPart = CFWL_Part::CheckBox;
92   param.m_rtPart = m_rtBox;
93   pTheme->DrawBackground(&param);
94 
95   CFWL_ThemeText textParam;
96   textParam.m_pWidget = this;
97   textParam.m_iPart = CFWL_Part::Caption;
98   textParam.m_dwStates = dwStates;
99   textParam.m_pGraphics = pGraphics;
100   if (pMatrix)
101     textParam.m_matrix.Concat(*pMatrix);
102   textParam.m_rtPart = m_rtCaption;
103   textParam.m_wsText = L"Check box";
104   textParam.m_dwTTOStyles = m_dwTTOStyles;
105   textParam.m_iTTOAlign = m_iTTOAlign;
106   pTheme->DrawText(&textParam);
107 }
108 
SetCheckState(int32_t iCheck)109 void CFWL_CheckBox::SetCheckState(int32_t iCheck) {
110   m_pProperties->m_dwStates &= ~FWL_STATE_CKB_CheckMask;
111   switch (iCheck) {
112     case 1:
113       m_pProperties->m_dwStates |= FWL_STATE_CKB_Checked;
114       break;
115     case 2:
116       if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_CKB_3State)
117         m_pProperties->m_dwStates |= FWL_STATE_CKB_Neutral;
118       break;
119     default:
120       break;
121   }
122   RepaintRect(m_rtClient);
123 }
124 
Layout()125 void CFWL_CheckBox::Layout() {
126   m_pProperties->m_rtWidget.width =
127       FXSYS_round(m_pProperties->m_rtWidget.width);
128   m_pProperties->m_rtWidget.height =
129       FXSYS_round(m_pProperties->m_rtWidget.height);
130   m_rtClient = GetClientRect();
131 
132   FX_FLOAT fTextLeft = m_rtClient.left + m_fBoxHeight;
133   m_rtBox = CFX_RectF(m_rtClient.TopLeft(), m_fBoxHeight, m_fBoxHeight);
134   m_rtCaption = CFX_RectF(fTextLeft, m_rtClient.top,
135                           m_rtClient.right() - fTextLeft, m_rtClient.height);
136   m_rtCaption.Inflate(-kCaptionMargin, -kCaptionMargin);
137 
138   CFX_RectF rtFocus(m_rtCaption.left, m_rtCaption.top, m_rtCaption.width,
139                     m_rtCaption.height);
140 
141   CalcTextRect(L"Check box", m_pProperties->m_pThemeProvider, m_dwTTOStyles,
142                m_iTTOAlign, rtFocus);
143 
144   m_rtFocus = CFX_RectF(m_rtCaption.TopLeft(),
145                         std::max(m_rtCaption.width, rtFocus.width),
146                         std::min(m_rtCaption.height, rtFocus.height));
147   m_rtFocus.Inflate(1, 1);
148 }
149 
GetPartStates() const150 uint32_t CFWL_CheckBox::GetPartStates() const {
151   int32_t dwStates = CFWL_PartState_Normal;
152   if ((m_pProperties->m_dwStates & FWL_STATE_CKB_CheckMask) ==
153       FWL_STATE_CKB_Neutral) {
154     dwStates = CFWL_PartState_Neutral;
155   } else if ((m_pProperties->m_dwStates & FWL_STATE_CKB_CheckMask) ==
156              FWL_STATE_CKB_Checked) {
157     dwStates = CFWL_PartState_Checked;
158   }
159   if (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled)
160     dwStates |= CFWL_PartState_Disabled;
161   else if (m_pProperties->m_dwStates & FWL_STATE_CKB_Hovered)
162     dwStates |= CFWL_PartState_Hovered;
163   else if (m_pProperties->m_dwStates & FWL_STATE_CKB_Pressed)
164     dwStates |= CFWL_PartState_Pressed;
165   else
166     dwStates |= CFWL_PartState_Normal;
167   if (m_pProperties->m_dwStates & FWL_WGTSTATE_Focused)
168     dwStates |= CFWL_PartState_Focused;
169   return dwStates;
170 }
171 
UpdateTextOutStyles()172 void CFWL_CheckBox::UpdateTextOutStyles() {
173   m_iTTOAlign = FDE_TTOALIGNMENT_TopLeft;
174   m_dwTTOStyles = 0;
175   m_dwTTOStyles |= FDE_TTOSTYLE_SingleLine;
176 }
177 
NextStates()178 void CFWL_CheckBox::NextStates() {
179   uint32_t dwFirststate = m_pProperties->m_dwStates;
180   if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_CKB_RadioButton) {
181     if ((m_pProperties->m_dwStates & FWL_STATE_CKB_CheckMask) ==
182         FWL_STATE_CKB_Unchecked) {
183       CFWL_WidgetMgr* pWidgetMgr = GetOwnerApp()->GetWidgetMgr();
184       if (!pWidgetMgr->IsFormDisabled()) {
185         std::vector<CFWL_Widget*> radioarr =
186             pWidgetMgr->GetSameGroupRadioButton(this);
187         for (const auto& pWidget : radioarr) {
188           CFWL_CheckBox* pCheckBox = static_cast<CFWL_CheckBox*>(pWidget);
189           if (pCheckBox != this &&
190               pCheckBox->GetStates() & FWL_STATE_CKB_Checked) {
191             pCheckBox->SetCheckState(0);
192             m_pWidgetMgr->RepaintWidget(
193                 pCheckBox, CFX_RectF(0, 0, pCheckBox->GetWidgetRect().Size()));
194             break;
195           }
196         }
197       }
198       m_pProperties->m_dwStates |= FWL_STATE_CKB_Checked;
199     }
200   } else {
201     if ((m_pProperties->m_dwStates & FWL_STATE_CKB_CheckMask) ==
202         FWL_STATE_CKB_Neutral) {
203       m_pProperties->m_dwStates &= ~FWL_STATE_CKB_CheckMask;
204       if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_CKB_3State)
205         m_pProperties->m_dwStates |= FWL_STATE_CKB_Checked;
206     } else if ((m_pProperties->m_dwStates & FWL_STATE_CKB_CheckMask) ==
207                FWL_STATE_CKB_Checked) {
208       m_pProperties->m_dwStates &= ~FWL_STATE_CKB_CheckMask;
209     } else {
210       if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_CKB_3State)
211         m_pProperties->m_dwStates |= FWL_STATE_CKB_Neutral;
212       else
213         m_pProperties->m_dwStates |= FWL_STATE_CKB_Checked;
214     }
215   }
216 
217   RepaintRect(m_rtClient);
218   if (dwFirststate == m_pProperties->m_dwStates)
219     return;
220 
221   CFWL_Event wmCheckBoxState(CFWL_Event::Type::CheckStateChanged, this);
222   DispatchEvent(&wmCheckBoxState);
223 }
224 
OnProcessMessage(CFWL_Message * pMessage)225 void CFWL_CheckBox::OnProcessMessage(CFWL_Message* pMessage) {
226   if (!pMessage)
227     return;
228 
229   switch (pMessage->GetType()) {
230     case CFWL_Message::Type::SetFocus:
231       OnFocusChanged(true);
232       break;
233     case CFWL_Message::Type::KillFocus:
234       OnFocusChanged(false);
235       break;
236     case CFWL_Message::Type::Mouse: {
237       CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
238       switch (pMsg->m_dwCmd) {
239         case FWL_MouseCommand::LeftButtonDown:
240           OnLButtonDown();
241           break;
242         case FWL_MouseCommand::LeftButtonUp:
243           OnLButtonUp(pMsg);
244           break;
245         case FWL_MouseCommand::Move:
246           OnMouseMove(pMsg);
247           break;
248         case FWL_MouseCommand::Leave:
249           OnMouseLeave();
250           break;
251         default:
252           break;
253       }
254       break;
255     }
256     case CFWL_Message::Type::Key: {
257       CFWL_MessageKey* pKey = static_cast<CFWL_MessageKey*>(pMessage);
258       if (pKey->m_dwCmd == FWL_KeyCommand::KeyDown)
259         OnKeyDown(pKey);
260       break;
261     }
262     default:
263       break;
264   }
265 
266   CFWL_Widget::OnProcessMessage(pMessage);
267 }
268 
OnDrawWidget(CFX_Graphics * pGraphics,const CFX_Matrix * pMatrix)269 void CFWL_CheckBox::OnDrawWidget(CFX_Graphics* pGraphics,
270                                  const CFX_Matrix* pMatrix) {
271   DrawWidget(pGraphics, pMatrix);
272 }
273 
OnFocusChanged(bool bSet)274 void CFWL_CheckBox::OnFocusChanged(bool bSet) {
275   if (bSet)
276     m_pProperties->m_dwStates |= FWL_WGTSTATE_Focused;
277   else
278     m_pProperties->m_dwStates &= ~FWL_WGTSTATE_Focused;
279 
280   RepaintRect(m_rtClient);
281 }
282 
OnLButtonDown()283 void CFWL_CheckBox::OnLButtonDown() {
284   if (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled)
285     return;
286   if ((m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) == 0)
287     SetFocus(true);
288 
289   m_bBtnDown = true;
290   m_pProperties->m_dwStates &= ~FWL_STATE_CKB_Hovered;
291   m_pProperties->m_dwStates |= FWL_STATE_CKB_Pressed;
292   RepaintRect(m_rtClient);
293 }
294 
OnLButtonUp(CFWL_MessageMouse * pMsg)295 void CFWL_CheckBox::OnLButtonUp(CFWL_MessageMouse* pMsg) {
296   if (!m_bBtnDown)
297     return;
298 
299   m_bBtnDown = false;
300   if (!m_rtClient.Contains(pMsg->m_pos))
301     return;
302 
303   m_pProperties->m_dwStates |= FWL_STATE_CKB_Hovered;
304   m_pProperties->m_dwStates &= ~FWL_STATE_CKB_Pressed;
305   NextStates();
306 }
307 
OnMouseMove(CFWL_MessageMouse * pMsg)308 void CFWL_CheckBox::OnMouseMove(CFWL_MessageMouse* pMsg) {
309   if (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled)
310     return;
311 
312   bool bRepaint = false;
313   if (m_bBtnDown) {
314     if (m_rtClient.Contains(pMsg->m_pos)) {
315       if ((m_pProperties->m_dwStates & FWL_STATE_CKB_Pressed) == 0) {
316         bRepaint = true;
317         m_pProperties->m_dwStates |= FWL_STATE_CKB_Pressed;
318       }
319       if ((m_pProperties->m_dwStates & FWL_STATE_CKB_Hovered)) {
320         bRepaint = true;
321         m_pProperties->m_dwStates &= ~FWL_STATE_CKB_Hovered;
322       }
323     } else {
324       if (m_pProperties->m_dwStates & FWL_STATE_CKB_Pressed) {
325         bRepaint = true;
326         m_pProperties->m_dwStates &= ~FWL_STATE_CKB_Pressed;
327       }
328       if ((m_pProperties->m_dwStates & FWL_STATE_CKB_Hovered) == 0) {
329         bRepaint = true;
330         m_pProperties->m_dwStates |= FWL_STATE_CKB_Hovered;
331       }
332     }
333   } else {
334     if (m_rtClient.Contains(pMsg->m_pos)) {
335       if ((m_pProperties->m_dwStates & FWL_STATE_CKB_Hovered) == 0) {
336         bRepaint = true;
337         m_pProperties->m_dwStates |= FWL_STATE_CKB_Hovered;
338       }
339     }
340   }
341   if (bRepaint)
342     RepaintRect(m_rtBox);
343 }
344 
OnMouseLeave()345 void CFWL_CheckBox::OnMouseLeave() {
346   if (m_bBtnDown)
347     m_pProperties->m_dwStates |= FWL_STATE_CKB_Hovered;
348   else
349     m_pProperties->m_dwStates &= ~FWL_STATE_CKB_Hovered;
350 
351   RepaintRect(m_rtBox);
352 }
353 
OnKeyDown(CFWL_MessageKey * pMsg)354 void CFWL_CheckBox::OnKeyDown(CFWL_MessageKey* pMsg) {
355   if (pMsg->m_dwKeyCode == FWL_VKEY_Tab)
356     return;
357   if (pMsg->m_dwKeyCode == FWL_VKEY_Return ||
358       pMsg->m_dwKeyCode == FWL_VKEY_Space) {
359     NextStates();
360   }
361 }
362