Home | History | Annotate | Download | only in pwl
      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 
     18 CPWL_EditCtrl::CPWL_EditCtrl()
     19     : m_pEdit(new CPWL_EditImpl),
     20       m_pEditCaret(nullptr),
     21       m_bMouseDown(false),
     22       m_nCharSet(FX_CHARSET_Default) {}
     23 
     24 CPWL_EditCtrl::~CPWL_EditCtrl() {}
     25 
     26 void CPWL_EditCtrl::OnCreate(CreateParams* pParamsToAdjust) {
     27   pParamsToAdjust->eCursorType = FXCT_VBEAM;
     28 }
     29 
     30 void CPWL_EditCtrl::OnCreated() {
     31   SetFontSize(GetCreationParams().fFontSize);
     32 
     33   m_pEdit->SetFontMap(GetFontMap());
     34   m_pEdit->SetNotify(this);
     35   m_pEdit->Initialize();
     36 }
     37 
     38 bool 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 
     43 void 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 
     54 WideString CPWL_EditCtrl::GetSelectedText() {
     55   if (m_pEdit)
     56     return m_pEdit->GetSelectedText();
     57 
     58   return WideString();
     59 }
     60 
     61 void 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 
     69 bool CPWL_EditCtrl::RePosChildWnd() {
     70   m_pEdit->SetPlateRect(GetClientRect());
     71   return true;
     72 }
     73 
     74 void CPWL_EditCtrl::SetScrollInfo(const PWL_SCROLL_INFO& info) {
     75   if (CPWL_Wnd* pChild = GetVScrollBar())
     76     pChild->SetScrollInfo(info);
     77 }
     78 
     79 void CPWL_EditCtrl::SetScrollPosition(float pos) {
     80   if (CPWL_Wnd* pChild = GetVScrollBar())
     81     pChild->SetScrollPosition(pos);
     82 }
     83 
     84 void CPWL_EditCtrl::ScrollWindowVertically(float pos) {
     85   m_pEdit->SetScrollPos(CFX_PointF(m_pEdit->GetScrollPos().x, pos));
     86 }
     87 
     88 void CPWL_EditCtrl::CreateChildWnd(const CreateParams& cp) {
     89   if (!IsReadOnly())
     90     CreateEditCaret(cp);
     91 }
     92 
     93 void 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 
    110 void CPWL_EditCtrl::SetFontSize(float fFontSize) {
    111   m_pEdit->SetFontSize(fFontSize);
    112 }
    113 
    114 float CPWL_EditCtrl::GetFontSize() const {
    115   return m_pEdit->GetFontSize();
    116 }
    117 
    118 bool 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 
    191 bool 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 
    263 bool 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 
    279 bool 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 
    294 bool 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 
    303 void 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 
    314 void 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 
    332 bool 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 
    349 WideString CPWL_EditCtrl::GetText() const {
    350   return m_pEdit->GetText();
    351 }
    352 
    353 void CPWL_EditCtrl::SetSelection(int32_t nStartChar, int32_t nEndChar) {
    354   m_pEdit->SetSelection(nStartChar, nEndChar);
    355 }
    356 
    357 void CPWL_EditCtrl::GetSelection(int32_t& nStartChar, int32_t& nEndChar) const {
    358   m_pEdit->GetSelection(nStartChar, nEndChar);
    359 }
    360 
    361 void CPWL_EditCtrl::ClearSelection() {
    362   if (!IsReadOnly())
    363     m_pEdit->ClearSelection();
    364 }
    365 
    366 void CPWL_EditCtrl::SelectAll() {
    367   m_pEdit->SelectAll();
    368 }
    369 
    370 void CPWL_EditCtrl::SetScrollPos(const CFX_PointF& point) {
    371   m_pEdit->SetScrollPos(point);
    372 }
    373 
    374 CFX_PointF CPWL_EditCtrl::GetScrollPos() const {
    375   return m_pEdit->GetScrollPos();
    376 }
    377 
    378 void CPWL_EditCtrl::CopyText() {}
    379 
    380 void CPWL_EditCtrl::PasteText() {}
    381 
    382 void CPWL_EditCtrl::CutText() {}
    383 
    384 void CPWL_EditCtrl::InsertWord(uint16_t word, int32_t nCharset) {
    385   if (!IsReadOnly())
    386     m_pEdit->InsertWord(word, nCharset);
    387 }
    388 
    389 void CPWL_EditCtrl::InsertReturn() {
    390   if (!IsReadOnly())
    391     m_pEdit->InsertReturn();
    392 }
    393 
    394 void CPWL_EditCtrl::Delete() {
    395   if (!IsReadOnly())
    396     m_pEdit->Delete();
    397 }
    398 
    399 void CPWL_EditCtrl::Backspace() {
    400   if (!IsReadOnly())
    401     m_pEdit->Backspace();
    402 }
    403 
    404 bool CPWL_EditCtrl::CanUndo() const {
    405   return !IsReadOnly() && m_pEdit->CanUndo();
    406 }
    407 
    408 bool CPWL_EditCtrl::CanRedo() const {
    409   return !IsReadOnly() && m_pEdit->CanRedo();
    410 }
    411 
    412 void CPWL_EditCtrl::Redo() {
    413   if (CanRedo())
    414     m_pEdit->Redo();
    415 }
    416 
    417 void CPWL_EditCtrl::Undo() {
    418   if (CanUndo())
    419     m_pEdit->Undo();
    420 }
    421 
    422 int32_t CPWL_EditCtrl::GetCharSet() const {
    423   return m_nCharSet < 0 ? FX_CHARSET_Default : m_nCharSet;
    424 }
    425 
    426 void CPWL_EditCtrl::SetReadyToInput() {
    427   if (m_bMouseDown) {
    428     ReleaseCapture();
    429     m_bMouseDown = false;
    430   }
    431 }
    432