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