• 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_checkbox.h"
8 
9 #include <algorithm>
10 #include <utility>
11 
12 #include "xfa/fde/cfde_textout.h"
13 #include "xfa/fwl/cfwl_app.h"
14 #include "xfa/fwl/cfwl_event.h"
15 #include "xfa/fwl/cfwl_messagekey.h"
16 #include "xfa/fwl/cfwl_messagemouse.h"
17 #include "xfa/fwl/cfwl_notedriver.h"
18 #include "xfa/fwl/cfwl_themebackground.h"
19 #include "xfa/fwl/cfwl_themetext.h"
20 #include "xfa/fwl/cfwl_widgetmgr.h"
21 #include "xfa/fwl/fwl_widgetdef.h"
22 #include "xfa/fwl/ifwl_themeprovider.h"
23 
24 namespace {
25 
26 const int kCaptionMargin = 5;
27 
28 }  // namespace
29 
CFWL_CheckBox(CFWL_App * app)30 CFWL_CheckBox::CFWL_CheckBox(CFWL_App* app)
31     : CFWL_Widget(app, Properties(), nullptr) {
32   m_TTOStyles.single_line_ = true;
33 }
34 
35 CFWL_CheckBox::~CFWL_CheckBox() = default;
36 
GetClassID() const37 FWL_Type CFWL_CheckBox::GetClassID() const {
38   return FWL_Type::CheckBox;
39 }
40 
SetBoxSize(float fHeight)41 void CFWL_CheckBox::SetBoxSize(float fHeight) {
42   m_fBoxHeight = fHeight;
43 }
44 
Update()45 void CFWL_CheckBox::Update() {
46   if (IsLocked())
47     return;
48 
49   UpdateTextOutStyles();
50   Layout();
51 }
52 
DrawWidget(CFGAS_GEGraphics * pGraphics,const CFX_Matrix & matrix)53 void CFWL_CheckBox::DrawWidget(CFGAS_GEGraphics* pGraphics,
54                                const CFX_Matrix& matrix) {
55   if (!pGraphics)
56     return;
57 
58   if (HasBorder())
59     DrawBorder(pGraphics, CFWL_ThemePart::Part::kBorder, matrix);
60 
61   Mask<CFWL_PartState> dwStates = GetPartStates();
62   IFWL_ThemeProvider* pTheme = GetThemeProvider();
63   CFWL_ThemeBackground param(CFWL_ThemePart::Part::kBackground, this,
64                              pGraphics);
65   param.m_dwStates = dwStates;
66   param.m_matrix = matrix;
67   param.m_PartRect = m_ClientRect;
68   if (m_Properties.m_dwStates & FWL_STATE_WGT_Focused)
69     param.m_pRtData = &m_FocusRect;
70   pTheme->DrawBackground(param);
71 
72   CFWL_ThemeBackground checkParam(CFWL_ThemePart::Part::kCheckBox, this,
73                                   pGraphics);
74   checkParam.m_dwStates = dwStates;
75   checkParam.m_matrix = matrix;
76   checkParam.m_PartRect = m_BoxRect;
77   if (m_Properties.m_dwStates & FWL_STATE_WGT_Focused)
78     checkParam.m_pRtData = &m_FocusRect;
79   pTheme->DrawBackground(checkParam);
80 
81   CFWL_ThemeText textParam(CFWL_ThemePart::Part::kCaption, this, pGraphics);
82   textParam.m_dwStates = dwStates;
83   textParam.m_matrix = matrix;
84   textParam.m_PartRect = m_CaptionRect;
85   textParam.m_wsText = L"Check box";
86   textParam.m_dwTTOStyles = m_TTOStyles;
87   textParam.m_iTTOAlign = m_iTTOAlign;
88   pTheme->DrawText(textParam);
89 }
90 
SetCheckState(int32_t iCheck)91 void CFWL_CheckBox::SetCheckState(int32_t iCheck) {
92   m_Properties.m_dwStates &= ~FWL_STATE_CKB_CheckMask;
93   switch (iCheck) {
94     case 1:
95       m_Properties.m_dwStates |= FWL_STATE_CKB_Checked;
96       break;
97     case 2:
98       if (m_Properties.m_dwStyleExts & FWL_STYLEEXT_CKB_3State)
99         m_Properties.m_dwStates |= FWL_STATE_CKB_Neutral;
100       break;
101     default:
102       break;
103   }
104   RepaintRect(m_ClientRect);
105 }
106 
Layout()107 void CFWL_CheckBox::Layout() {
108   m_WidgetRect.width = FXSYS_roundf(m_WidgetRect.width);
109   m_WidgetRect.height = FXSYS_roundf(m_WidgetRect.height);
110   m_ClientRect = GetClientRect();
111 
112   float fTextLeft = m_ClientRect.left + m_fBoxHeight;
113   m_BoxRect = CFX_RectF(m_ClientRect.TopLeft(), m_fBoxHeight, m_fBoxHeight);
114   m_CaptionRect =
115       CFX_RectF(fTextLeft, m_ClientRect.top, m_ClientRect.right() - fTextLeft,
116                 m_ClientRect.height);
117   m_CaptionRect.Inflate(-kCaptionMargin, -kCaptionMargin);
118 
119   CFX_RectF rtFocus = m_CaptionRect;
120   CalcTextRect(L"Check box", m_TTOStyles, m_iTTOAlign, &rtFocus);
121   m_FocusRect = CFX_RectF(m_CaptionRect.TopLeft(),
122                           std::max(m_CaptionRect.width, rtFocus.width),
123                           std::min(m_CaptionRect.height, rtFocus.height));
124   m_FocusRect.Inflate(1, 1);
125 }
126 
GetPartStates() const127 Mask<CFWL_PartState> CFWL_CheckBox::GetPartStates() const {
128   Mask<CFWL_PartState> dwStates = CFWL_PartState::kNormal;
129   if ((m_Properties.m_dwStates & FWL_STATE_CKB_CheckMask) ==
130       FWL_STATE_CKB_Neutral) {
131     dwStates = CFWL_PartState::kNeutral;
132   } else if ((m_Properties.m_dwStates & FWL_STATE_CKB_CheckMask) ==
133              FWL_STATE_CKB_Checked) {
134     dwStates = CFWL_PartState::kChecked;
135   }
136   if (m_Properties.m_dwStates & FWL_STATE_WGT_Disabled)
137     dwStates |= CFWL_PartState::kDisabled;
138   else if (m_Properties.m_dwStates & FWL_STATE_CKB_Hovered)
139     dwStates |= CFWL_PartState::kHovered;
140   else if (m_Properties.m_dwStates & FWL_STATE_CKB_Pressed)
141     dwStates |= CFWL_PartState::kPressed;
142   else
143     dwStates |= CFWL_PartState::kNormal;
144   if (m_Properties.m_dwStates & FWL_STATE_WGT_Focused)
145     dwStates |= CFWL_PartState::kFocused;
146   return dwStates;
147 }
148 
UpdateTextOutStyles()149 void CFWL_CheckBox::UpdateTextOutStyles() {
150   m_iTTOAlign = FDE_TextAlignment::kTopLeft;
151   m_TTOStyles.Reset();
152   m_TTOStyles.single_line_ = true;
153 }
154 
NextStates()155 void CFWL_CheckBox::NextStates() {
156   uint32_t dwFirststate = m_Properties.m_dwStates;
157   if (m_Properties.m_dwStyleExts & FWL_STYLEEXT_CKB_RadioButton) {
158     if ((m_Properties.m_dwStates & FWL_STATE_CKB_CheckMask) ==
159         FWL_STATE_CKB_Unchecked) {
160       m_Properties.m_dwStates |= FWL_STATE_CKB_Checked;
161     }
162   } else {
163     if ((m_Properties.m_dwStates & FWL_STATE_CKB_CheckMask) ==
164         FWL_STATE_CKB_Neutral) {
165       m_Properties.m_dwStates &= ~FWL_STATE_CKB_CheckMask;
166       if (m_Properties.m_dwStyleExts & FWL_STYLEEXT_CKB_3State)
167         m_Properties.m_dwStates |= FWL_STATE_CKB_Checked;
168     } else if ((m_Properties.m_dwStates & FWL_STATE_CKB_CheckMask) ==
169                FWL_STATE_CKB_Checked) {
170       m_Properties.m_dwStates &= ~FWL_STATE_CKB_CheckMask;
171     } else {
172       if (m_Properties.m_dwStyleExts & FWL_STYLEEXT_CKB_3State)
173         m_Properties.m_dwStates |= FWL_STATE_CKB_Neutral;
174       else
175         m_Properties.m_dwStates |= FWL_STATE_CKB_Checked;
176     }
177   }
178 
179   RepaintRect(m_ClientRect);
180   if (dwFirststate == m_Properties.m_dwStates)
181     return;
182 
183   CFWL_Event wmCheckBoxState(CFWL_Event::Type::CheckStateChanged, this);
184   DispatchEvent(&wmCheckBoxState);
185 }
186 
OnProcessMessage(CFWL_Message * pMessage)187 void CFWL_CheckBox::OnProcessMessage(CFWL_Message* pMessage) {
188   switch (pMessage->GetType()) {
189     case CFWL_Message::Type::kSetFocus:
190       OnFocusGained();
191       break;
192     case CFWL_Message::Type::kKillFocus:
193       OnFocusLost();
194       break;
195     case CFWL_Message::Type::kMouse: {
196       CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
197       switch (pMsg->m_dwCmd) {
198         case CFWL_MessageMouse::MouseCommand::kLeftButtonDown:
199           OnLButtonDown();
200           break;
201         case CFWL_MessageMouse::MouseCommand::kLeftButtonUp:
202           OnLButtonUp(pMsg);
203           break;
204         case CFWL_MessageMouse::MouseCommand::kMove:
205           OnMouseMove(pMsg);
206           break;
207         case CFWL_MessageMouse::MouseCommand::kLeave:
208           OnMouseLeave();
209           break;
210         default:
211           break;
212       }
213       break;
214     }
215     case CFWL_Message::Type::kKey: {
216       CFWL_MessageKey* pKey = static_cast<CFWL_MessageKey*>(pMessage);
217       if (pKey->m_dwCmd == CFWL_MessageKey::KeyCommand::kKeyDown)
218         OnKeyDown(pKey);
219       break;
220     }
221     default:
222       break;
223   }
224   // Dst target could be |this|, continue only if not destroyed by above.
225   if (pMessage->GetDstTarget())
226     CFWL_Widget::OnProcessMessage(pMessage);
227 }
228 
OnDrawWidget(CFGAS_GEGraphics * pGraphics,const CFX_Matrix & matrix)229 void CFWL_CheckBox::OnDrawWidget(CFGAS_GEGraphics* pGraphics,
230                                  const CFX_Matrix& matrix) {
231   DrawWidget(pGraphics, matrix);
232 }
233 
OnFocusGained()234 void CFWL_CheckBox::OnFocusGained() {
235   m_Properties.m_dwStates |= FWL_STATE_WGT_Focused;
236   RepaintRect(m_ClientRect);
237 }
238 
OnFocusLost()239 void CFWL_CheckBox::OnFocusLost() {
240   m_Properties.m_dwStates &= ~FWL_STATE_WGT_Focused;
241   RepaintRect(m_ClientRect);
242 }
243 
OnLButtonDown()244 void CFWL_CheckBox::OnLButtonDown() {
245   if (m_Properties.m_dwStates & FWL_STATE_WGT_Disabled)
246     return;
247 
248   m_bBtnDown = true;
249   m_Properties.m_dwStates &= ~FWL_STATE_CKB_Hovered;
250   m_Properties.m_dwStates |= FWL_STATE_CKB_Pressed;
251   RepaintRect(m_ClientRect);
252 }
253 
OnLButtonUp(CFWL_MessageMouse * pMsg)254 void CFWL_CheckBox::OnLButtonUp(CFWL_MessageMouse* pMsg) {
255   if (!m_bBtnDown)
256     return;
257 
258   m_bBtnDown = false;
259   if (!m_ClientRect.Contains(pMsg->m_pos))
260     return;
261 
262   m_Properties.m_dwStates |= FWL_STATE_CKB_Hovered;
263   m_Properties.m_dwStates &= ~FWL_STATE_CKB_Pressed;
264   NextStates();
265 }
266 
OnMouseMove(CFWL_MessageMouse * pMsg)267 void CFWL_CheckBox::OnMouseMove(CFWL_MessageMouse* pMsg) {
268   if (m_Properties.m_dwStates & FWL_STATE_WGT_Disabled)
269     return;
270 
271   bool bRepaint = false;
272   if (m_bBtnDown) {
273     if (m_ClientRect.Contains(pMsg->m_pos)) {
274       if ((m_Properties.m_dwStates & FWL_STATE_CKB_Pressed) == 0) {
275         bRepaint = true;
276         m_Properties.m_dwStates |= FWL_STATE_CKB_Pressed;
277       }
278       if ((m_Properties.m_dwStates & FWL_STATE_CKB_Hovered)) {
279         bRepaint = true;
280         m_Properties.m_dwStates &= ~FWL_STATE_CKB_Hovered;
281       }
282     } else {
283       if (m_Properties.m_dwStates & FWL_STATE_CKB_Pressed) {
284         bRepaint = true;
285         m_Properties.m_dwStates &= ~FWL_STATE_CKB_Pressed;
286       }
287       if ((m_Properties.m_dwStates & FWL_STATE_CKB_Hovered) == 0) {
288         bRepaint = true;
289         m_Properties.m_dwStates |= FWL_STATE_CKB_Hovered;
290       }
291     }
292   } else {
293     if (m_ClientRect.Contains(pMsg->m_pos)) {
294       if ((m_Properties.m_dwStates & FWL_STATE_CKB_Hovered) == 0) {
295         bRepaint = true;
296         m_Properties.m_dwStates |= FWL_STATE_CKB_Hovered;
297       }
298     }
299   }
300   if (bRepaint)
301     RepaintRect(m_BoxRect);
302 }
303 
OnMouseLeave()304 void CFWL_CheckBox::OnMouseLeave() {
305   if (m_bBtnDown)
306     m_Properties.m_dwStates |= FWL_STATE_CKB_Hovered;
307   else
308     m_Properties.m_dwStates &= ~FWL_STATE_CKB_Hovered;
309 
310   RepaintRect(m_BoxRect);
311 }
312 
OnKeyDown(CFWL_MessageKey * pMsg)313 void CFWL_CheckBox::OnKeyDown(CFWL_MessageKey* pMsg) {
314   if (pMsg->m_dwKeyCodeOrChar == XFA_FWL_VKEY_Tab)
315     return;
316   if (pMsg->m_dwKeyCodeOrChar == XFA_FWL_VKEY_Return ||
317       pMsg->m_dwKeyCodeOrChar == XFA_FWL_VKEY_Space) {
318     NextStates();
319   }
320 }
321