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 "fpdfsdk/pwl/cpwl_edit_ctrl.h" 8 9#include "core/fpdfdoc/cpvt_word.h" 10#include "core/fxge/fx_font.h" 11#include "fpdfsdk/pwl/cpwl_caret.h" 12#include "fpdfsdk/pwl/cpwl_edit_impl.h" 13#include "fpdfsdk/pwl/cpwl_font_map.h" 14#include "fpdfsdk/pwl/cpwl_scroll_bar.h" 15#include "fpdfsdk/pwl/cpwl_wnd.h" 16#include "public/fpdf_fwlevent.h" 17 18CPWL_EditCtrl::CPWL_EditCtrl() 19 : m_pEdit(new CPWL_EditImpl), 20 m_pEditCaret(nullptr), 21 m_bMouseDown(false), 22 m_nCharSet(FX_CHARSET_Default) {} 23 24CPWL_EditCtrl::~CPWL_EditCtrl() {} 25 26void CPWL_EditCtrl::OnCreate(CreateParams* pParamsToAdjust) { 27 pParamsToAdjust->eCursorType = FXCT_VBEAM; 28} 29 30void CPWL_EditCtrl::OnCreated() { 31 SetFontSize(GetCreationParams().fFontSize); 32 33 m_pEdit->SetFontMap(GetFontMap()); 34 m_pEdit->SetNotify(this); 35 m_pEdit->Initialize(); 36} 37 38bool CPWL_EditCtrl::IsWndHorV() { 39 CFX_Matrix mt = GetWindowMatrix(); 40 return mt.Transform(CFX_PointF(1, 1)).y == mt.Transform(CFX_PointF(0, 1)).y; 41} 42 43void CPWL_EditCtrl::SetCursor() { 44 if (IsValid()) { 45 if (CFX_SystemHandler* pSH = GetSystemHandler()) { 46 if (IsWndHorV()) 47 pSH->SetCursor(FXCT_VBEAM); 48 else 49 pSH->SetCursor(FXCT_HBEAM); 50 } 51 } 52} 53 54WideString CPWL_EditCtrl::GetSelectedText() { 55 if (m_pEdit) 56 return m_pEdit->GetSelectedText(); 57 58 return WideString(); 59} 60 61void CPWL_EditCtrl::ReplaceSelection(const WideString& text) { 62 if (!m_pEdit) 63 return; 64 65 m_pEdit->ClearSelection(); 66 m_pEdit->InsertText(text, FX_CHARSET_Default); 67} 68 69bool CPWL_EditCtrl::RePosChildWnd() { 70 m_pEdit->SetPlateRect(GetClientRect()); 71 return true; 72} 73 74void CPWL_EditCtrl::SetScrollInfo(const PWL_SCROLL_INFO& info) { 75 if (CPWL_Wnd* pChild = GetVScrollBar()) 76 pChild->SetScrollInfo(info); 77} 78 79void CPWL_EditCtrl::SetScrollPosition(float pos) { 80 if (CPWL_Wnd* pChild = GetVScrollBar()) 81 pChild->SetScrollPosition(pos); 82} 83 84void CPWL_EditCtrl::ScrollWindowVertically(float pos) { 85 m_pEdit->SetScrollPos(CFX_PointF(m_pEdit->GetScrollPos().x, pos)); 86} 87 88void CPWL_EditCtrl::CreateChildWnd(const CreateParams& cp) { 89 if (!IsReadOnly()) 90 CreateEditCaret(cp); 91} 92 93void CPWL_EditCtrl::CreateEditCaret(const CreateParams& cp) { 94 if (m_pEditCaret) 95 return; 96 97 m_pEditCaret = new CPWL_Caret; 98 m_pEditCaret->SetInvalidRect(GetClientRect()); 99 100 CreateParams ecp = cp; 101 ecp.pParentWnd = this; 102 ecp.dwFlags = PWS_CHILD | PWS_NOREFRESHCLIP; 103 ecp.dwBorderWidth = 0; 104 ecp.nBorderStyle = BorderStyle::SOLID; 105 ecp.rcRectWnd = CFX_FloatRect(); 106 107 m_pEditCaret->Create(ecp); 108} 109 110void CPWL_EditCtrl::SetFontSize(float fFontSize) { 111 m_pEdit->SetFontSize(fFontSize); 112} 113 114float CPWL_EditCtrl::GetFontSize() const { 115 return m_pEdit->GetFontSize(); 116} 117 118bool CPWL_EditCtrl::OnKeyDown(uint16_t nChar, uint32_t nFlag) { 119 if (m_bMouseDown) 120 return true; 121 122 bool bRet = CPWL_Wnd::OnKeyDown(nChar, nFlag); 123 124 // FILTER 125 switch (nChar) { 126 default: 127 return false; 128 case FWL_VKEY_Delete: 129 case FWL_VKEY_Up: 130 case FWL_VKEY_Down: 131 case FWL_VKEY_Left: 132 case FWL_VKEY_Right: 133 case FWL_VKEY_Home: 134 case FWL_VKEY_End: 135 case FWL_VKEY_Insert: 136 case 'C': 137 case 'V': 138 case 'X': 139 case 'A': 140 case 'Z': 141 case 'c': 142 case 'v': 143 case 'x': 144 case 'a': 145 case 'z': 146 break; 147 } 148 149 if (nChar == FWL_VKEY_Delete && m_pEdit->IsSelected()) 150 nChar = FWL_VKEY_Unknown; 151 152 switch (nChar) { 153 case FWL_VKEY_Delete: 154 Delete(); 155 return true; 156 case FWL_VKEY_Insert: 157 if (IsSHIFTpressed(nFlag)) 158 PasteText(); 159 return true; 160 case FWL_VKEY_Up: 161 m_pEdit->OnVK_UP(IsSHIFTpressed(nFlag), false); 162 return true; 163 case FWL_VKEY_Down: 164 m_pEdit->OnVK_DOWN(IsSHIFTpressed(nFlag), false); 165 return true; 166 case FWL_VKEY_Left: 167 m_pEdit->OnVK_LEFT(IsSHIFTpressed(nFlag), false); 168 return true; 169 case FWL_VKEY_Right: 170 m_pEdit->OnVK_RIGHT(IsSHIFTpressed(nFlag), false); 171 return true; 172 case FWL_VKEY_Home: 173 m_pEdit->OnVK_HOME(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag)); 174 return true; 175 case FWL_VKEY_End: 176 m_pEdit->OnVK_END(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag)); 177 return true; 178 case FWL_VKEY_Unknown: 179 if (!IsSHIFTpressed(nFlag)) 180 ClearSelection(); 181 else 182 CutText(); 183 return true; 184 default: 185 break; 186 } 187 188 return bRet; 189} 190 191bool CPWL_EditCtrl::OnChar(uint16_t nChar, uint32_t nFlag) { 192 if (m_bMouseDown) 193 return true; 194 195 CPWL_Wnd::OnChar(nChar, nFlag); 196 197 // FILTER 198 switch (nChar) { 199 case 0x0A: 200 case 0x1B: 201 return false; 202 default: 203 break; 204 } 205 206 bool bCtrl = IsCTRLpressed(nFlag); 207 bool bAlt = IsALTpressed(nFlag); 208 bool bShift = IsSHIFTpressed(nFlag); 209 210 uint16_t word = nChar; 211 212 if (bCtrl && !bAlt) { 213 switch (nChar) { 214 case 'C' - 'A' + 1: 215 CopyText(); 216 return true; 217 case 'V' - 'A' + 1: 218 PasteText(); 219 return true; 220 case 'X' - 'A' + 1: 221 CutText(); 222 return true; 223 case 'A' - 'A' + 1: 224 SelectAll(); 225 return true; 226 case 'Z' - 'A' + 1: 227 if (bShift) 228 Redo(); 229 else 230 Undo(); 231 return true; 232 default: 233 if (nChar < 32) 234 return false; 235 } 236 } 237 238 if (IsReadOnly()) 239 return true; 240 241 if (m_pEdit->IsSelected() && word == FWL_VKEY_Back) 242 word = FWL_VKEY_Unknown; 243 244 ClearSelection(); 245 246 switch (word) { 247 case FWL_VKEY_Back: 248 Backspace(); 249 break; 250 case FWL_VKEY_Return: 251 InsertReturn(); 252 break; 253 case FWL_VKEY_Unknown: 254 break; 255 default: 256 InsertWord(word, GetCharSet()); 257 break; 258 } 259 260 return true; 261} 262 263bool CPWL_EditCtrl::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) { 264 CPWL_Wnd::OnLButtonDown(point, nFlag); 265 266 if (ClientHitTest(point)) { 267 if (m_bMouseDown && !InvalidateRect(nullptr)) 268 return true; 269 270 m_bMouseDown = true; 271 SetCapture(); 272 273 m_pEdit->OnMouseDown(point, IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag)); 274 } 275 276 return true; 277} 278 279bool CPWL_EditCtrl::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) { 280 CPWL_Wnd::OnLButtonUp(point, nFlag); 281 282 if (m_bMouseDown) { 283 // can receive keybord message 284 if (ClientHitTest(point) && !IsFocused()) 285 SetFocus(); 286 287 ReleaseCapture(); 288 m_bMouseDown = false; 289 } 290 291 return true; 292} 293 294bool CPWL_EditCtrl::OnMouseMove(const CFX_PointF& point, uint32_t nFlag) { 295 CPWL_Wnd::OnMouseMove(point, nFlag); 296 297 if (m_bMouseDown) 298 m_pEdit->OnMouseMove(point, false, false); 299 300 return true; 301} 302 303void CPWL_EditCtrl::SetEditCaret(bool bVisible) { 304 CFX_PointF ptHead; 305 CFX_PointF ptFoot; 306 if (bVisible) 307 GetCaretInfo(&ptHead, &ptFoot); 308 309 SetCaret(bVisible, ptHead, ptFoot); 310 // Note, |this| may no longer be viable at this point. If more work needs to 311 // be done, check the return value of SetCaret(). 312} 313 314void CPWL_EditCtrl::GetCaretInfo(CFX_PointF* ptHead, CFX_PointF* ptFoot) const { 315 CPWL_EditImpl_Iterator* pIterator = m_pEdit->GetIterator(); 316 pIterator->SetAt(m_pEdit->GetCaret()); 317 CPVT_Word word; 318 CPVT_Line line; 319 if (pIterator->GetWord(word)) { 320 ptHead->x = word.ptWord.x + word.fWidth; 321 ptHead->y = word.ptWord.y + word.fAscent; 322 ptFoot->x = word.ptWord.x + word.fWidth; 323 ptFoot->y = word.ptWord.y + word.fDescent; 324 } else if (pIterator->GetLine(line)) { 325 ptHead->x = line.ptLine.x; 326 ptHead->y = line.ptLine.y + line.fLineAscent; 327 ptFoot->x = line.ptLine.x; 328 ptFoot->y = line.ptLine.y + line.fLineDescent; 329 } 330} 331 332bool CPWL_EditCtrl::SetCaret(bool bVisible, 333 const CFX_PointF& ptHead, 334 const CFX_PointF& ptFoot) { 335 if (!m_pEditCaret) 336 return true; 337 338 if (!IsFocused() || m_pEdit->IsSelected()) 339 bVisible = false; 340 341 ObservedPtr thisObserved(this); 342 m_pEditCaret->SetCaret(bVisible, ptHead, ptFoot); 343 if (!thisObserved) 344 return false; 345 346 return true; 347} 348 349WideString CPWL_EditCtrl::GetText() const { 350 return m_pEdit->GetText(); 351} 352 353void CPWL_EditCtrl::SetSelection(int32_t nStartChar, int32_t nEndChar) { 354 m_pEdit->SetSelection(nStartChar, nEndChar); 355} 356 357void CPWL_EditCtrl::GetSelection(int32_t& nStartChar, int32_t& nEndChar) const { 358 m_pEdit->GetSelection(nStartChar, nEndChar); 359} 360 361void CPWL_EditCtrl::ClearSelection() { 362 if (!IsReadOnly()) 363 m_pEdit->ClearSelection(); 364} 365 366void CPWL_EditCtrl::SelectAll() { 367 m_pEdit->SelectAll(); 368} 369 370void CPWL_EditCtrl::SetScrollPos(const CFX_PointF& point) { 371 m_pEdit->SetScrollPos(point); 372} 373 374CFX_PointF CPWL_EditCtrl::GetScrollPos() const { 375 return m_pEdit->GetScrollPos(); 376} 377 378void CPWL_EditCtrl::CopyText() {} 379 380void CPWL_EditCtrl::PasteText() {} 381 382void CPWL_EditCtrl::CutText() {} 383 384void CPWL_EditCtrl::InsertWord(uint16_t word, int32_t nCharset) { 385 if (!IsReadOnly()) 386 m_pEdit->InsertWord(word, nCharset); 387} 388 389void CPWL_EditCtrl::InsertReturn() { 390 if (!IsReadOnly()) 391 m_pEdit->InsertReturn(); 392} 393 394void CPWL_EditCtrl::Delete() { 395 if (!IsReadOnly()) 396 m_pEdit->Delete(); 397} 398 399void CPWL_EditCtrl::Backspace() { 400 if (!IsReadOnly()) 401 m_pEdit->Backspace(); 402} 403 404bool CPWL_EditCtrl::CanUndo() const { 405 return !IsReadOnly() && m_pEdit->CanUndo(); 406} 407 408bool CPWL_EditCtrl::CanRedo() const { 409 return !IsReadOnly() && m_pEdit->CanRedo(); 410} 411 412void CPWL_EditCtrl::Redo() { 413 if (CanRedo()) 414 m_pEdit->Redo(); 415} 416 417void CPWL_EditCtrl::Undo() { 418 if (CanUndo()) 419 m_pEdit->Undo(); 420} 421 422int32_t CPWL_EditCtrl::GetCharSet() const { 423 return m_nCharSet < 0 ? FX_CHARSET_Default : m_nCharSet; 424} 425 426void CPWL_EditCtrl::SetReadyToInput() { 427 if (m_bMouseDown) { 428 ReleaseCapture(); 429 m_bMouseDown = false; 430 } 431} 432