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