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_pushbutton.h" 8 9 #include <memory> 10 #include <utility> 11 12 #include "third_party/base/ptr_util.h" 13 #include "xfa/fde/cfde_textout.h" 14 #include "xfa/fwl/cfwl_event.h" 15 #include "xfa/fwl/cfwl_eventmouse.h" 16 #include "xfa/fwl/cfwl_messagekey.h" 17 #include "xfa/fwl/cfwl_messagemouse.h" 18 #include "xfa/fwl/cfwl_notedriver.h" 19 #include "xfa/fwl/cfwl_themebackground.h" 20 #include "xfa/fwl/cfwl_themetext.h" 21 #include "xfa/fwl/ifwl_themeprovider.h" 22 23 CFWL_PushButton::CFWL_PushButton(const CFWL_App* app) 24 : CFWL_Widget(app, pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr), 25 m_bBtnDown(false) {} 26 27 CFWL_PushButton::~CFWL_PushButton() {} 28 29 FWL_Type CFWL_PushButton::GetClassID() const { 30 return FWL_Type::PushButton; 31 } 32 33 void CFWL_PushButton::SetStates(uint32_t dwStates) { 34 if (dwStates & FWL_WGTSTATE_Disabled) { 35 m_pProperties->m_dwStates = FWL_WGTSTATE_Disabled; 36 return; 37 } 38 CFWL_Widget::SetStates(dwStates); 39 } 40 41 void CFWL_PushButton::Update() { 42 if (IsLocked()) 43 return; 44 if (!m_pProperties->m_pThemeProvider) 45 m_pProperties->m_pThemeProvider = GetAvailableTheme(); 46 47 m_rtClient = GetClientRect(); 48 m_rtCaption = m_rtClient; 49 } 50 51 void CFWL_PushButton::DrawWidget(CXFA_Graphics* pGraphics, 52 const CFX_Matrix& matrix) { 53 if (!pGraphics) 54 return; 55 if (!m_pProperties->m_pThemeProvider) 56 return; 57 58 if (HasBorder()) { 59 DrawBorder(pGraphics, CFWL_Part::Border, m_pProperties->m_pThemeProvider, 60 matrix); 61 } 62 DrawBkground(pGraphics, m_pProperties->m_pThemeProvider, &matrix); 63 } 64 65 void CFWL_PushButton::DrawBkground(CXFA_Graphics* pGraphics, 66 IFWL_ThemeProvider* pTheme, 67 const CFX_Matrix* pMatrix) { 68 CFWL_ThemeBackground param; 69 param.m_pWidget = this; 70 param.m_iPart = CFWL_Part::Background; 71 param.m_dwStates = GetPartStates(); 72 param.m_pGraphics = pGraphics; 73 if (pMatrix) 74 param.m_matrix.Concat(*pMatrix); 75 param.m_rtPart = m_rtClient; 76 if (m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) 77 param.m_pData = &m_rtCaption; 78 pTheme->DrawBackground(¶m); 79 } 80 81 uint32_t CFWL_PushButton::GetPartStates() { 82 uint32_t dwStates = CFWL_PartState_Normal; 83 if (m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) 84 dwStates |= CFWL_PartState_Focused; 85 if (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled) 86 dwStates = CFWL_PartState_Disabled; 87 else if (m_pProperties->m_dwStates & FWL_STATE_PSB_Pressed) 88 dwStates |= CFWL_PartState_Pressed; 89 else if (m_pProperties->m_dwStates & FWL_STATE_PSB_Hovered) 90 dwStates |= CFWL_PartState_Hovered; 91 return dwStates; 92 } 93 94 void CFWL_PushButton::OnProcessMessage(CFWL_Message* pMessage) { 95 if (!pMessage) 96 return; 97 if (!IsEnabled()) 98 return; 99 100 switch (pMessage->GetType()) { 101 case CFWL_Message::Type::SetFocus: 102 OnFocusChanged(pMessage, true); 103 break; 104 case CFWL_Message::Type::KillFocus: 105 OnFocusChanged(pMessage, false); 106 break; 107 case CFWL_Message::Type::Mouse: { 108 CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage); 109 switch (pMsg->m_dwCmd) { 110 case FWL_MouseCommand::LeftButtonDown: 111 OnLButtonDown(pMsg); 112 break; 113 case FWL_MouseCommand::LeftButtonUp: 114 OnLButtonUp(pMsg); 115 break; 116 case FWL_MouseCommand::Move: 117 OnMouseMove(pMsg); 118 break; 119 case FWL_MouseCommand::Leave: 120 OnMouseLeave(pMsg); 121 break; 122 default: 123 break; 124 } 125 break; 126 } 127 case CFWL_Message::Type::Key: { 128 CFWL_MessageKey* pKey = static_cast<CFWL_MessageKey*>(pMessage); 129 if (pKey->m_dwCmd == FWL_KeyCommand::KeyDown) 130 OnKeyDown(pKey); 131 break; 132 } 133 default: 134 break; 135 } 136 CFWL_Widget::OnProcessMessage(pMessage); 137 } 138 139 void CFWL_PushButton::OnDrawWidget(CXFA_Graphics* pGraphics, 140 const CFX_Matrix& matrix) { 141 DrawWidget(pGraphics, matrix); 142 } 143 144 void CFWL_PushButton::OnFocusChanged(CFWL_Message* pMsg, bool bSet) { 145 if (bSet) 146 m_pProperties->m_dwStates |= FWL_WGTSTATE_Focused; 147 else 148 m_pProperties->m_dwStates &= ~FWL_WGTSTATE_Focused; 149 150 RepaintRect(m_rtClient); 151 } 152 153 void CFWL_PushButton::OnLButtonDown(CFWL_MessageMouse* pMsg) { 154 if ((m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) == 0) 155 SetFocus(true); 156 157 m_bBtnDown = true; 158 m_pProperties->m_dwStates |= FWL_STATE_PSB_Hovered; 159 m_pProperties->m_dwStates |= FWL_STATE_PSB_Pressed; 160 RepaintRect(m_rtClient); 161 } 162 163 void CFWL_PushButton::OnLButtonUp(CFWL_MessageMouse* pMsg) { 164 m_bBtnDown = false; 165 if (m_rtClient.Contains(pMsg->m_pos)) { 166 m_pProperties->m_dwStates &= ~FWL_STATE_PSB_Pressed; 167 m_pProperties->m_dwStates |= FWL_STATE_PSB_Hovered; 168 } else { 169 m_pProperties->m_dwStates &= ~FWL_STATE_PSB_Hovered; 170 m_pProperties->m_dwStates &= ~FWL_STATE_PSB_Pressed; 171 } 172 if (m_rtClient.Contains(pMsg->m_pos)) { 173 CFWL_Event wmClick(CFWL_Event::Type::Click, this); 174 DispatchEvent(&wmClick); 175 } 176 RepaintRect(m_rtClient); 177 } 178 179 void CFWL_PushButton::OnMouseMove(CFWL_MessageMouse* pMsg) { 180 bool bRepaint = false; 181 if (m_bBtnDown) { 182 if (m_rtClient.Contains(pMsg->m_pos)) { 183 if ((m_pProperties->m_dwStates & FWL_STATE_PSB_Pressed) == 0) { 184 m_pProperties->m_dwStates |= FWL_STATE_PSB_Pressed; 185 bRepaint = true; 186 } 187 if (m_pProperties->m_dwStates & FWL_STATE_PSB_Hovered) { 188 m_pProperties->m_dwStates &= ~FWL_STATE_PSB_Hovered; 189 bRepaint = true; 190 } 191 } else { 192 if (m_pProperties->m_dwStates & FWL_STATE_PSB_Pressed) { 193 m_pProperties->m_dwStates &= ~FWL_STATE_PSB_Pressed; 194 bRepaint = true; 195 } 196 if ((m_pProperties->m_dwStates & FWL_STATE_PSB_Hovered) == 0) { 197 m_pProperties->m_dwStates |= FWL_STATE_PSB_Hovered; 198 bRepaint = true; 199 } 200 } 201 } else { 202 if (!m_rtClient.Contains(pMsg->m_pos)) 203 return; 204 if ((m_pProperties->m_dwStates & FWL_STATE_PSB_Hovered) == 0) { 205 m_pProperties->m_dwStates |= FWL_STATE_PSB_Hovered; 206 bRepaint = true; 207 } 208 } 209 if (bRepaint) 210 RepaintRect(m_rtClient); 211 } 212 213 void CFWL_PushButton::OnMouseLeave(CFWL_MessageMouse* pMsg) { 214 m_bBtnDown = false; 215 m_pProperties->m_dwStates &= ~FWL_STATE_PSB_Hovered; 216 m_pProperties->m_dwStates &= ~FWL_STATE_PSB_Pressed; 217 RepaintRect(m_rtClient); 218 } 219 220 void CFWL_PushButton::OnKeyDown(CFWL_MessageKey* pMsg) { 221 if (pMsg->m_dwKeyCode != FWL_VKEY_Return) 222 return; 223 224 CFWL_EventMouse wmMouse(this); 225 wmMouse.m_dwCmd = FWL_MouseCommand::LeftButtonUp; 226 DispatchEvent(&wmMouse); 227 228 CFWL_Event wmClick(CFWL_Event::Type::Click, this); 229 DispatchEvent(&wmClick); 230 } 231