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/src/foxitlib.h" 8 #include "xfa/src/fwl/src/core/include/fwl_targetimp.h" 9 #include "xfa/src/fwl/src/core/include/fwl_noteimp.h" 10 #include "xfa/src/fwl/src/core/include/fwl_widgetimp.h" 11 #include "xfa/src/fwl/src/core/include/fwl_panelimp.h" 12 #include "xfa/src/fwl/src/core/include/fwl_formimp.h" 13 #include "xfa/src/fwl/src/basewidget/include/fwl_tooltipctrlimp.h" 14 15 // static 16 IFWL_ToolTip* IFWL_ToolTip::Create(const CFWL_WidgetImpProperties& properties, 17 IFWL_Widget* pOuter) { 18 IFWL_ToolTip* pToolTip = new IFWL_ToolTip; 19 CFWL_ToolTipImp* pToolTipImpl = new CFWL_ToolTipImp(properties, pOuter); 20 pToolTip->SetImpl(pToolTipImpl); 21 pToolTipImpl->SetInterface(pToolTip); 22 return pToolTip; 23 } 24 FWL_ERR IFWL_ToolTip::SetAnchor(const CFX_RectF& rtAnchor) { 25 return static_cast<CFWL_ToolTipImp*>(GetImpl())->SetAnchor(rtAnchor); 26 } 27 FWL_ERR IFWL_ToolTip::Show() { 28 return static_cast<CFWL_ToolTipImp*>(GetImpl())->Show(); 29 } 30 FWL_ERR IFWL_ToolTip::Hide() { 31 return static_cast<CFWL_ToolTipImp*>(GetImpl())->Hide(); 32 } 33 IFWL_ToolTip::IFWL_ToolTip() { 34 } 35 CFWL_ToolTipImp::CFWL_ToolTipImp(const CFWL_WidgetImpProperties& properties, 36 IFWL_Widget* pOuter) 37 : CFWL_FormImp(properties, pOuter), 38 m_bBtnDown(FALSE), 39 m_dwTTOStyles(FDE_TTOSTYLE_SingleLine), 40 m_iTTOAlign(FDE_TTOALIGNMENT_Center), 41 m_hTimerShow(NULL), 42 m_hTimerHide(NULL), 43 m_pTimer(NULL) { 44 m_rtClient.Set(0, 0, 0, 0); 45 m_rtCaption.Set(0, 0, 0, 0); 46 m_rtAnchor.Set(0, 0, 0, 0); 47 m_TimerShow.m_pToolTip = this; 48 m_TimerHide.m_pToolTip = this; 49 } 50 CFWL_ToolTipImp::~CFWL_ToolTipImp() { 51 if (m_pTimer) { 52 delete m_pTimer; 53 m_pTimer = NULL; 54 } 55 } 56 FWL_ERR CFWL_ToolTipImp::GetClassName(CFX_WideString& wsClass) const { 57 wsClass = FWL_CLASS_ToolTip; 58 return FWL_ERR_Succeeded; 59 } 60 FX_DWORD CFWL_ToolTipImp::GetClassID() const { 61 return FWL_CLASSHASH_ToolTip; 62 } 63 FWL_ERR CFWL_ToolTipImp::Initialize() { 64 m_pProperties->m_dwStyles |= FWL_WGTSTYLE_Popup; 65 m_pProperties->m_dwStyles &= ~FWL_WGTSTYLE_Child; 66 if (CFWL_WidgetImp::Initialize() != FWL_ERR_Succeeded) 67 return FWL_ERR_Indefinite; 68 m_pDelegate = new CFWL_ToolTipImpDelegate(this); 69 return FWL_ERR_Succeeded; 70 } 71 FWL_ERR CFWL_ToolTipImp::Finalize() { 72 delete m_pDelegate; 73 m_pDelegate = nullptr; 74 return CFWL_WidgetImp::Finalize(); 75 } 76 FWL_ERR CFWL_ToolTipImp::GetWidgetRect(CFX_RectF& rect, FX_BOOL bAutoSize) { 77 if (bAutoSize) { 78 rect.Set(0, 0, 0, 0); 79 if (m_pProperties->m_pThemeProvider == NULL) { 80 m_pProperties->m_pThemeProvider = GetAvailableTheme(); 81 } 82 CFX_WideString wsCaption; 83 IFWL_ToolTipDP* pData = 84 static_cast<IFWL_ToolTipDP*>(m_pProperties->m_pDataProvider); 85 if (pData) { 86 pData->GetCaption(m_pInterface, wsCaption); 87 } 88 int32_t iLen = wsCaption.GetLength(); 89 if (iLen > 0) { 90 CFX_SizeF sz = CalcTextSize(wsCaption, m_pProperties->m_pThemeProvider); 91 rect.Set(0, 0, sz.x, sz.y); 92 rect.width += FWL_WGTCAPACITY_CXBorder * 25; 93 rect.height += FWL_WGTCAPACITY_CYBorder * 8; 94 } 95 CFWL_WidgetImp::GetWidgetRect(rect, TRUE); 96 } else { 97 rect = m_pProperties->m_rtWidget; 98 } 99 return FWL_ERR_Succeeded; 100 } 101 FWL_ERR CFWL_ToolTipImp::Update() { 102 if (IsLocked()) { 103 return FWL_ERR_Indefinite; 104 } 105 if (!m_pProperties->m_pThemeProvider) { 106 m_pProperties->m_pThemeProvider = GetAvailableTheme(); 107 } 108 UpdateTextOutStyles(); 109 GetClientRect(m_rtClient); 110 m_rtCaption = m_rtClient; 111 return FWL_ERR_Succeeded; 112 } 113 FWL_ERR CFWL_ToolTipImp::GetClientRect(CFX_RectF& rect) { 114 FX_FLOAT x = 0; 115 FX_FLOAT y = 0; 116 FX_FLOAT t = 0; 117 IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider; 118 if (pTheme) { 119 CFWL_ThemePart part; 120 part.m_pWidget = m_pInterface; 121 x = *static_cast<FX_FLOAT*>( 122 pTheme->GetCapacity(&part, FWL_WGTCAPACITY_CXBorder)); 123 y = *static_cast<FX_FLOAT*>( 124 pTheme->GetCapacity(&part, FWL_WGTCAPACITY_CYBorder)); 125 } 126 rect = m_pProperties->m_rtWidget; 127 rect.Offset(-rect.left, -rect.top); 128 rect.Deflate(x, t, x, y); 129 return FWL_ERR_Succeeded; 130 } 131 FWL_ERR CFWL_ToolTipImp::DrawWidget(CFX_Graphics* pGraphics, 132 const CFX_Matrix* pMatrix) { 133 IFWL_ToolTipTarget* toolTipTarget = 134 CFWL_ToolTipContainer::getInstance()->GetCurrentToolTipTarget(); 135 if (toolTipTarget && !toolTipTarget->UseDefaultTheme()) { 136 return toolTipTarget->DrawToolTip(pGraphics, pMatrix, m_pInterface); 137 } 138 if (!pGraphics) 139 return FWL_ERR_Indefinite; 140 if (!m_pProperties->m_pThemeProvider) 141 return FWL_ERR_Indefinite; 142 IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider; 143 DrawBkground(pGraphics, pTheme, pMatrix); 144 DrawText(pGraphics, pTheme, pMatrix); 145 return FWL_ERR_Succeeded; 146 } 147 void CFWL_ToolTipImp::DrawBkground(CFX_Graphics* pGraphics, 148 IFWL_ThemeProvider* pTheme, 149 const CFX_Matrix* pMatrix) { 150 CFWL_ThemeBackground param; 151 param.m_pWidget = m_pInterface; 152 param.m_iPart = FWL_PART_TTP_Background; 153 param.m_dwStates = m_pProperties->m_dwStates; 154 param.m_pGraphics = pGraphics; 155 if (pMatrix) { 156 param.m_matrix.Concat(*pMatrix); 157 } 158 param.m_rtPart = m_rtClient; 159 if (m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) { 160 param.m_pData = &m_rtCaption; 161 } 162 pTheme->DrawBackground(¶m); 163 } 164 void CFWL_ToolTipImp::DrawText(CFX_Graphics* pGraphics, 165 IFWL_ThemeProvider* pTheme, 166 const CFX_Matrix* pMatrix) { 167 if (!m_pProperties->m_pDataProvider) 168 return; 169 CFX_WideString wsCaption; 170 m_pProperties->m_pDataProvider->GetCaption(m_pInterface, wsCaption); 171 if (wsCaption.IsEmpty()) { 172 return; 173 } 174 CFWL_ThemeText param; 175 param.m_pWidget = m_pInterface; 176 param.m_iPart = FWL_PART_TTP_Caption; 177 param.m_dwStates = m_pProperties->m_dwStates; 178 param.m_pGraphics = pGraphics; 179 if (pMatrix) { 180 param.m_matrix.Concat(*pMatrix); 181 } 182 param.m_rtPart = m_rtCaption; 183 param.m_wsText = wsCaption; 184 param.m_dwTTOStyles = m_dwTTOStyles; 185 param.m_iTTOAlign = m_iTTOAlign; 186 pTheme->DrawText(¶m); 187 } 188 void CFWL_ToolTipImp::UpdateTextOutStyles() { 189 m_iTTOAlign = FDE_TTOALIGNMENT_Center; 190 m_dwTTOStyles = FDE_TTOSTYLE_SingleLine; 191 if (m_pProperties->m_dwStyleExes & FWL_WGTSTYLE_RTLReading) { 192 m_dwTTOStyles |= FDE_TTOSTYLE_RTL; 193 } 194 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_TTP_Multiline) { 195 m_dwTTOStyles &= ~FDE_TTOSTYLE_SingleLine; 196 } 197 } 198 FWL_ERR CFWL_ToolTipImp::SetAnchor(const CFX_RectF& rtAnchor) { 199 m_rtAnchor = rtAnchor; 200 return TRUE; 201 } 202 FWL_ERR CFWL_ToolTipImp::Show() { 203 IFWL_ToolTipDP* pData = 204 static_cast<IFWL_ToolTipDP*>(m_pProperties->m_pDataProvider); 205 int32_t nInitDelay = pData->GetInitialDelay(m_pInterface); 206 if ((m_pProperties->m_dwStates & FWL_WGTSTATE_Invisible)) { 207 m_hTimerShow = FWL_StartTimer(&m_TimerShow, nInitDelay, FALSE); 208 } 209 return TRUE; 210 } 211 FWL_ERR CFWL_ToolTipImp::Hide() { 212 SetStates(FWL_WGTSTATE_Invisible, TRUE); 213 if (m_hTimerHide) { 214 FWL_StopTimer(m_hTimerHide); 215 m_hTimerHide = NULL; 216 } 217 if (m_hTimerShow) { 218 FWL_StopTimer(m_hTimerShow); 219 m_hTimerShow = NULL; 220 } 221 return TRUE; 222 } 223 FWL_ERR CFWL_ToolTipImp::SetStates(FX_DWORD dwStates, FX_BOOL bSet) { 224 if ((dwStates & FWL_WGTSTATE_Invisible) && !bSet) { 225 IFWL_ToolTipDP* pData = 226 static_cast<IFWL_ToolTipDP*>(m_pProperties->m_pDataProvider); 227 int32_t nAutoPopDelay = pData->GetAutoPopDelay(m_pInterface); 228 m_hTimerHide = FWL_StartTimer(&m_TimerHide, nAutoPopDelay, FALSE); 229 } 230 return CFWL_WidgetImp::SetStates(dwStates, bSet); 231 } 232 void CFWL_ToolTipImp::RefreshToolTipPos() { 233 if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_TTP_NoAnchor) == 0) { 234 CFX_RectF rtPopup; 235 CFX_RectF rtWidget(m_pProperties->m_rtWidget); 236 CFX_RectF rtAnchor(m_rtAnchor); 237 rtPopup.Set(0, 0, 0, 0); 238 FX_FLOAT fx = rtAnchor.Center().x + 20; 239 FX_FLOAT fy = rtAnchor.Center().y + 20; 240 rtPopup.Set(fx, fy, rtWidget.Width(), rtWidget.Height()); 241 FX_FLOAT fScreenWidth = 0; 242 FX_FLOAT fScreenHeight = 0; 243 GetScreenSize(fScreenWidth, fScreenHeight); 244 if (rtPopup.bottom() > fScreenHeight) { 245 rtPopup.Offset(0, fScreenHeight - rtPopup.bottom()); 246 } 247 if (rtPopup.right() > fScreenWidth) { 248 rtPopup.Offset(fScreenWidth - rtPopup.right(), 0); 249 } 250 if (rtPopup.left < 0) { 251 rtPopup.Offset(0 - rtPopup.left, 0); 252 } 253 if (rtPopup.top < 0) { 254 rtPopup.Offset(0, 0 - rtPopup.top); 255 } 256 SetWidgetRect(rtPopup); 257 Update(); 258 } 259 } 260 CFWL_ToolTipImp::CFWL_ToolTipTimer::CFWL_ToolTipTimer(CFWL_ToolTipImp* pToolTip) 261 : m_pToolTip(pToolTip) {} 262 int32_t CFWL_ToolTipImp::CFWL_ToolTipTimer::Run(FWL_HTIMER hTimer) { 263 if (m_pToolTip->m_hTimerShow == hTimer && m_pToolTip->m_hTimerShow) { 264 if (m_pToolTip->GetStates() & FWL_WGTSTATE_Invisible) { 265 m_pToolTip->SetStates(FWL_WGTSTATE_Invisible, FALSE); 266 m_pToolTip->RefreshToolTipPos(); 267 FWL_StopTimer(m_pToolTip->m_hTimerShow); 268 m_pToolTip->m_hTimerShow = NULL; 269 return TRUE; 270 } 271 } 272 if (m_pToolTip->m_hTimerHide == hTimer && m_pToolTip->m_hTimerHide) { 273 m_pToolTip->SetStates(FWL_WGTSTATE_Invisible, TRUE); 274 FWL_StopTimer(m_pToolTip->m_hTimerHide); 275 m_pToolTip->m_hTimerHide = NULL; 276 return TRUE; 277 } 278 return TRUE; 279 } 280 CFWL_ToolTipImpDelegate::CFWL_ToolTipImpDelegate(CFWL_ToolTipImp* pOwner) 281 : m_pOwner(pOwner) {} 282 int32_t CFWL_ToolTipImpDelegate::OnProcessMessage(CFWL_Message* pMessage) { 283 return CFWL_WidgetImpDelegate::OnProcessMessage(pMessage); 284 } 285 FWL_ERR CFWL_ToolTipImpDelegate::OnProcessEvent(CFWL_Event* pEvent) { 286 return FWL_ERR_Succeeded; 287 } 288 FWL_ERR CFWL_ToolTipImpDelegate::OnDrawWidget(CFX_Graphics* pGraphics, 289 const CFX_Matrix* pMatrix) { 290 return m_pOwner->DrawWidget(pGraphics, pMatrix); 291 } 292