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