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 <algorithm>
8
9#include "xfa/src/foxitlib.h"
10#include "xfa/src/fwl/src/core/include/fwl_threadimp.h"
11#include "xfa/src/fwl/src/core/include/fwl_appimp.h"
12#include "xfa/src/fwl/src/core/include/fwl_targetimp.h"
13#include "xfa/src/fwl/src/core/include/fwl_noteimp.h"
14#include "xfa/src/fwl/src/core/include/fwl_widgetimp.h"
15#include "xfa/src/fwl/src/core/include/fwl_widgetmgrimp.h"
16#include "xfa/src/fwl/src/basewidget/include/fwl_caretimp.h"
17#include "xfa/src/fwl/src/basewidget/include/fwl_comboboximp.h"
18#include "xfa/src/fwl/src/basewidget/include/fwl_editimp.h"
19#include "xfa/src/fwl/src/basewidget/include/fwl_scrollbarimp.h"
20
21// static
22IFWL_Edit* IFWL_Edit::Create(const CFWL_WidgetImpProperties& properties,
23                             IFWL_Widget* pOuter) {
24  IFWL_Edit* pEdit = new IFWL_Edit;
25  CFWL_EditImp* pEditImpl = new CFWL_EditImp(properties, pOuter);
26  pEdit->SetImpl(pEditImpl);
27  pEditImpl->SetInterface(pEdit);
28  return pEdit;
29}
30// static
31IFWL_Edit* IFWL_Edit::CreateComboEdit(
32    const CFWL_WidgetImpProperties& properties,
33    IFWL_Widget* pOuter) {
34  IFWL_Edit* pEdit = new IFWL_Edit;
35  CFWL_EditImp* pComboEditImpl = new CFWL_ComboEditImp(properties, pOuter);
36  pEdit->SetImpl(pComboEditImpl);
37  pComboEditImpl->SetInterface(pEdit);
38  return pEdit;
39}
40IFWL_Edit::IFWL_Edit() {}
41FWL_ERR IFWL_Edit::SetText(const CFX_WideString& wsText) {
42  return static_cast<CFWL_EditImp*>(GetImpl())->SetText(wsText);
43}
44int32_t IFWL_Edit::GetTextLength() const {
45  return static_cast<CFWL_EditImp*>(GetImpl())->GetTextLength();
46}
47FWL_ERR IFWL_Edit::GetText(CFX_WideString& wsText,
48                           int32_t nStart,
49                           int32_t nCount) const {
50  return static_cast<CFWL_EditImp*>(GetImpl())->GetText(wsText, nStart, nCount);
51}
52FWL_ERR IFWL_Edit::ClearText() {
53  return static_cast<CFWL_EditImp*>(GetImpl())->ClearText();
54}
55int32_t IFWL_Edit::GetCaretPos() const {
56  return static_cast<CFWL_EditImp*>(GetImpl())->GetCaretPos();
57}
58int32_t IFWL_Edit::SetCaretPos(int32_t nIndex, FX_BOOL bBefore) {
59  return static_cast<CFWL_EditImp*>(GetImpl())->SetCaretPos(nIndex, bBefore);
60}
61FWL_ERR IFWL_Edit::AddSelRange(int32_t nStart, int32_t nCount) {
62  return static_cast<CFWL_EditImp*>(GetImpl())->AddSelRange(nStart, nCount);
63}
64int32_t IFWL_Edit::CountSelRanges() {
65  return static_cast<CFWL_EditImp*>(GetImpl())->CountSelRanges();
66}
67int32_t IFWL_Edit::GetSelRange(int32_t nIndex, int32_t& nStart) {
68  return static_cast<CFWL_EditImp*>(GetImpl())->GetSelRange(nIndex, nStart);
69}
70FWL_ERR IFWL_Edit::ClearSelections() {
71  return static_cast<CFWL_EditImp*>(GetImpl())->ClearSelections();
72}
73int32_t IFWL_Edit::GetLimit() {
74  return static_cast<CFWL_EditImp*>(GetImpl())->GetLimit();
75}
76FWL_ERR IFWL_Edit::SetLimit(int32_t nLimit) {
77  return static_cast<CFWL_EditImp*>(GetImpl())->SetLimit(nLimit);
78}
79FWL_ERR IFWL_Edit::SetAliasChar(FX_WCHAR wAlias) {
80  return static_cast<CFWL_EditImp*>(GetImpl())->SetAliasChar(wAlias);
81}
82FWL_ERR IFWL_Edit::SetFormatString(const CFX_WideString& wsFormat) {
83  return static_cast<CFWL_EditImp*>(GetImpl())->SetFormatString(wsFormat);
84}
85FWL_ERR IFWL_Edit::Insert(int32_t nStart,
86                          const FX_WCHAR* lpText,
87                          int32_t nLen) {
88  return static_cast<CFWL_EditImp*>(GetImpl())->Insert(nStart, lpText, nLen);
89}
90FWL_ERR IFWL_Edit::DeleteSelections() {
91  return static_cast<CFWL_EditImp*>(GetImpl())->DeleteSelections();
92}
93FWL_ERR IFWL_Edit::DeleteRange(int32_t nStart, int32_t nCount) {
94  return static_cast<CFWL_EditImp*>(GetImpl())->DeleteRange(nStart, nCount);
95}
96FWL_ERR IFWL_Edit::ReplaceSelections(const CFX_WideStringC& wsReplace) {
97  return static_cast<CFWL_EditImp*>(GetImpl())->ReplaceSelections(wsReplace);
98}
99FWL_ERR IFWL_Edit::Replace(int32_t nStart,
100                           int32_t nLen,
101                           const CFX_WideStringC& wsReplace) {
102  return static_cast<CFWL_EditImp*>(GetImpl())
103      ->Replace(nStart, nLen, wsReplace);
104}
105FWL_ERR IFWL_Edit::DoClipboard(int32_t iCmd) {
106  return static_cast<CFWL_EditImp*>(GetImpl())->DoClipboard(iCmd);
107}
108FX_BOOL IFWL_Edit::Copy(CFX_WideString& wsCopy) {
109  return static_cast<CFWL_EditImp*>(GetImpl())->Copy(wsCopy);
110}
111FX_BOOL IFWL_Edit::Cut(CFX_WideString& wsCut) {
112  return static_cast<CFWL_EditImp*>(GetImpl())->Cut(wsCut);
113}
114FX_BOOL IFWL_Edit::Paste(const CFX_WideString& wsPaste) {
115  return static_cast<CFWL_EditImp*>(GetImpl())->Paste(wsPaste);
116}
117FX_BOOL IFWL_Edit::Delete() {
118  return static_cast<CFWL_EditImp*>(GetImpl())->Delete();
119}
120FX_BOOL IFWL_Edit::Redo(const CFX_ByteStringC& bsRecord) {
121  return static_cast<CFWL_EditImp*>(GetImpl())->Redo(bsRecord);
122}
123FX_BOOL IFWL_Edit::Undo(const CFX_ByteStringC& bsRecord) {
124  return static_cast<CFWL_EditImp*>(GetImpl())->Undo(bsRecord);
125}
126FX_BOOL IFWL_Edit::Undo() {
127  return static_cast<CFWL_EditImp*>(GetImpl())->Undo();
128}
129FX_BOOL IFWL_Edit::Redo() {
130  return static_cast<CFWL_EditImp*>(GetImpl())->Redo();
131}
132FX_BOOL IFWL_Edit::CanUndo() {
133  return static_cast<CFWL_EditImp*>(GetImpl())->CanUndo();
134}
135FX_BOOL IFWL_Edit::CanRedo() {
136  return static_cast<CFWL_EditImp*>(GetImpl())->CanRedo();
137}
138FWL_ERR IFWL_Edit::SetTabWidth(FX_FLOAT fTabWidth, FX_BOOL bEquidistant) {
139  return static_cast<CFWL_EditImp*>(GetImpl())
140      ->SetTabWidth(fTabWidth, bEquidistant);
141}
142FWL_ERR IFWL_Edit::SetOuter(IFWL_Widget* pOuter) {
143  return static_cast<CFWL_EditImp*>(GetImpl())->SetOuter(pOuter);
144}
145FWL_ERR IFWL_Edit::SetNumberRange(int32_t iMin, int32_t iMax) {
146  return static_cast<CFWL_EditImp*>(GetImpl())->SetNumberRange(iMin, iMax);
147}
148FWL_ERR IFWL_Edit::SetBackColor(FX_DWORD dwColor) {
149  return static_cast<CFWL_EditImp*>(GetImpl())->SetBackgroundColor(dwColor);
150}
151FWL_ERR IFWL_Edit::SetFont(const CFX_WideString& wsFont, FX_FLOAT fSize) {
152  return static_cast<CFWL_EditImp*>(GetImpl())->SetFont(wsFont, fSize);
153}
154void IFWL_Edit::SetScrollOffset(FX_FLOAT fScrollOffset) {
155  return static_cast<CFWL_EditImp*>(GetImpl())->SetScrollOffset(fScrollOffset);
156}
157FX_BOOL IFWL_Edit::GetSuggestWords(CFX_PointF pointf,
158                                   CFX_ByteStringArray& sSuggest) {
159  return static_cast<CFWL_EditImp*>(GetImpl())
160      ->GetSuggestWords(pointf, sSuggest);
161}
162FX_BOOL IFWL_Edit::ReplaceSpellCheckWord(CFX_PointF pointf,
163                                         const CFX_ByteStringC& bsReplace) {
164  return static_cast<CFWL_EditImp*>(GetImpl())
165      ->ReplaceSpellCheckWord(pointf, bsReplace);
166}
167#define FWL_EDIT_Margin 3
168CFWL_EditImp::CFWL_EditImp(const CFWL_WidgetImpProperties& properties,
169                           IFWL_Widget* pOuter)
170    : CFWL_WidgetImp(properties, pOuter),
171      m_fVAlignOffset(0.0f),
172      m_fScrollOffsetX(0.0f),
173      m_fScrollOffsetY(0.0f),
174      m_pEdtEngine(NULL),
175      m_bLButtonDown(FALSE),
176      m_nSelStart(0),
177      m_nLimit(-1),
178      m_fSpaceAbove(0),
179      m_fSpaceBelow(0),
180      m_fFontSize(0),
181      m_bSetRange(FALSE),
182      m_iMin(-1),
183      m_iMax(0xFFFFFFF),
184      m_backColor(0),
185      m_updateBackColor(FALSE),
186      m_iCurRecord(-1),
187      m_iMaxRecord(128) {
188  m_rtClient.Reset();
189  m_rtEngine.Reset();
190  m_rtStatic.Reset();
191}
192CFWL_EditImp::~CFWL_EditImp() {
193  if (m_pEdtEngine) {
194    m_pEdtEngine->Release();
195    m_pEdtEngine = NULL;
196  }
197  ClearRecord();
198}
199FWL_ERR CFWL_EditImp::GetClassName(CFX_WideString& wsClass) const {
200  wsClass = FWL_CLASS_Edit;
201  return FWL_ERR_Succeeded;
202}
203FX_DWORD CFWL_EditImp::GetClassID() const {
204  return FWL_CLASSHASH_Edit;
205}
206FWL_ERR CFWL_EditImp::Initialize() {
207  if (CFWL_WidgetImp::Initialize() != FWL_ERR_Succeeded)
208    return FWL_ERR_Indefinite;
209  if (!m_pDelegate) {
210    m_pDelegate = new CFWL_EditImpDelegate(this);
211  }
212  InitCaret();
213  if (!m_pEdtEngine) {
214    InitEngine();
215  }
216  return FWL_ERR_Succeeded;
217}
218FWL_ERR CFWL_EditImp::Finalize() {
219  if (m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) {
220    ShowCaret(FALSE);
221  }
222  if (m_pHorzScrollBar) {
223    m_pHorzScrollBar->Finalize();
224  }
225  if (m_pVertScrollBar) {
226    m_pVertScrollBar->Finalize();
227  }
228  delete m_pDelegate;
229  m_pDelegate = nullptr;
230  return CFWL_WidgetImp::Finalize();
231}
232FWL_ERR CFWL_EditImp::GetWidgetRect(CFX_RectF& rect, FX_BOOL bAutoSize) {
233  if (bAutoSize) {
234    rect.Set(0, 0, 0, 0);
235    if (m_pEdtEngine) {
236      int32_t iTextLen = m_pEdtEngine->GetTextLength();
237      if (iTextLen > 0) {
238        CFX_WideString wsText;
239        m_pEdtEngine->GetText(wsText, 0);
240        CFX_SizeF sz = CalcTextSize(
241            wsText, m_pProperties->m_pThemeProvider,
242            m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_MultiLine);
243        rect.Set(0, 0, sz.x, sz.y);
244      }
245    }
246    CFWL_WidgetImp::GetWidgetRect(rect, TRUE);
247  } else {
248    rect = m_pProperties->m_rtWidget;
249    if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_OuterScrollbar) {
250      if (IsShowScrollBar(TRUE)) {
251        FX_FLOAT* pfWidth = static_cast<FX_FLOAT*>(
252            GetThemeCapacity(FWL_WGTCAPACITY_ScrollBarWidth));
253        rect.width += *pfWidth;
254        rect.width += FWL_EDIT_Margin;
255      }
256      if (IsShowScrollBar(FALSE)) {
257        FX_FLOAT* pfWidth = static_cast<FX_FLOAT*>(
258            GetThemeCapacity(FWL_WGTCAPACITY_ScrollBarWidth));
259        rect.height += *pfWidth;
260        rect.height += FWL_EDIT_Margin;
261      }
262    }
263  }
264  return FWL_ERR_Succeeded;
265}
266FWL_ERR CFWL_EditImp::SetStates(FX_DWORD dwStates, FX_BOOL bSet) {
267  if ((m_pProperties->m_dwStates & FWL_WGTSTATE_Invisible) ||
268      (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled)) {
269    ShowCaret(FALSE);
270  }
271  return CFWL_WidgetImp::SetStates(dwStates, bSet);
272}
273FWL_ERR CFWL_EditImp::SetWidgetRect(const CFX_RectF& rect) {
274  return CFWL_WidgetImp::SetWidgetRect(rect);
275}
276FWL_ERR CFWL_EditImp::Update() {
277  if (IsLocked()) {
278    return FWL_ERR_Indefinite;
279  }
280  if (!m_pProperties->m_pThemeProvider) {
281    m_pProperties->m_pThemeProvider = GetAvailableTheme();
282  }
283  Layout();
284  if (m_rtClient.IsEmpty()) {
285    return FWL_ERR_Indefinite;
286  }
287  UpdateEditEngine();
288  UpdateVAlignment();
289  UpdateScroll();
290  InitCaret();
291  return FWL_ERR_Succeeded;
292}
293FX_DWORD CFWL_EditImp::HitTest(FX_FLOAT fx, FX_FLOAT fy) {
294  if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_OuterScrollbar) {
295    if (IsShowScrollBar(TRUE)) {
296      CFX_RectF rect;
297      m_pVertScrollBar->GetWidgetRect(rect);
298      if (rect.Contains(fx, fy)) {
299        return FWL_WGTHITTEST_VScrollBar;
300      }
301    }
302    if (IsShowScrollBar(FALSE)) {
303      CFX_RectF rect;
304      m_pHorzScrollBar->GetWidgetRect(rect);
305      if (rect.Contains(fx, fy)) {
306        return FWL_WGTHITTEST_HScrollBar;
307      }
308    }
309  }
310  if (m_rtClient.Contains(fx, fy)) {
311    return FWL_WGTHITTEST_Edit;
312  }
313  return FWL_WGTHITTEST_Unknown;
314}
315#define FX_EDIT_ISLATINWORD(u)                                     \
316  (u == 0x2D || (u <= 0x005A && u >= 0x0041) ||                    \
317   (u <= 0x007A && u >= 0x0061) || (u <= 0x02AF && u >= 0x00C0) || \
318   u == 0x0027)
319static void AddSquigglyPath(CFX_Path& PathData,
320                            FX_FLOAT fStartX,
321                            FX_FLOAT fEndX,
322                            FX_FLOAT fY,
323                            FX_FLOAT fStep) {
324  PathData.MoveTo(fStartX, fY);
325  FX_FLOAT fx;
326  int32_t i;
327  for (i = 1, fx = fStartX + fStep; fx < fEndX; fx += fStep, i++) {
328    PathData.LineTo(fx, fY + (i & 1) * fStep);
329  }
330}
331void CFWL_EditImp::AddSpellCheckObj(CFX_Path& PathData,
332                                    int32_t nStart,
333                                    int32_t nCount,
334                                    FX_FLOAT fOffSetX,
335                                    FX_FLOAT fOffSetY) {
336  FX_FLOAT fStartX = 0.0f;
337  FX_FLOAT fEndX = 0.0f;
338  FX_FLOAT fY = 0.0f;
339  FX_FLOAT fStep = 0.0f;
340  IFDE_TxtEdtPage* pPage = m_pEdtEngine->GetPage(0);
341  CFX_RectFArray rectArray;
342  CFX_RectF rectText;
343  const FDE_TXTEDTPARAMS* txtEdtParams = m_pEdtEngine->GetEditParams();
344  FX_FLOAT fAsent = (FX_FLOAT)txtEdtParams->pFont->GetAscent() *
345                    txtEdtParams->fFontSize / 1000;
346  pPage->CalcRangeRectArray(nStart, nCount, rectArray);
347  for (int i = 0; i < rectArray.GetSize(); i++) {
348    rectText = rectArray.GetAt(i);
349    fY = rectText.top + fAsent + fOffSetY;
350    fStep = txtEdtParams->fFontSize / 16.0f;
351    fStartX = rectText.left + fOffSetX;
352    fEndX = fStartX + rectText.Width();
353    AddSquigglyPath(PathData, fStartX, fEndX, fY, fStep);
354  }
355}
356int32_t CFWL_EditImp::GetWordAtPoint(CFX_PointF pointf, int32_t& nCount) {
357  return 0;
358}
359FX_BOOL CFWL_EditImp::GetSuggestWords(CFX_PointF pointf,
360                                      CFX_ByteStringArray& sSuggest) {
361  int32_t nWordCount = 0;
362  int32_t nWordStart = GetWordAtPoint(pointf, nWordCount);
363  if (nWordCount < 1) {
364    return FALSE;
365  }
366  CFX_WideString wsSpell;
367  GetText(wsSpell, nWordStart, nWordCount);
368  CFX_ByteString sLatinWord;
369  for (int i = 0; i < nWordCount; i++) {
370    if (!FX_EDIT_ISLATINWORD(wsSpell[i])) {
371      break;
372    }
373    sLatinWord += (FX_CHAR)wsSpell[i];
374  }
375  if (sLatinWord.IsEmpty()) {
376    return FALSE;
377  }
378  CFWL_EvtEdtCheckWord checkWordEvent;
379  checkWordEvent.m_pSrcTarget = m_pInterface;
380  checkWordEvent.bsWord = sLatinWord;
381  checkWordEvent.bCheckWord = TRUE;
382  DispatchEvent(&checkWordEvent);
383  if (checkWordEvent.bCheckWord) {
384    return FALSE;
385  }
386  CFWL_EvtEdtGetSuggestWords suggestWordsEvent;
387  suggestWordsEvent.m_pSrcTarget = m_pInterface;
388  suggestWordsEvent.bsWord = sLatinWord;
389  suggestWordsEvent.bsArraySuggestWords = sSuggest;
390  suggestWordsEvent.bSuggestWords = FALSE;
391  DispatchEvent(&checkWordEvent);
392  return suggestWordsEvent.bSuggestWords;
393}
394FX_BOOL CFWL_EditImp::ReplaceSpellCheckWord(CFX_PointF pointf,
395                                            const CFX_ByteStringC& bsReplace) {
396  int32_t nWordCount = 0;
397  int32_t nWordStart = GetWordAtPoint(pointf, nWordCount);
398  if (nWordCount < 1) {
399    return FALSE;
400  }
401  CFX_WideString wsSpell;
402  GetText(wsSpell, nWordStart, nWordCount);
403  for (int i = 0; i < nWordCount; i++) {
404    if (!FX_EDIT_ISLATINWORD(wsSpell[i])) {
405      nWordCount = i;
406      break;
407    }
408  }
409  int32_t nDestLen = bsReplace.GetLength();
410  CFX_WideString wsDest;
411  FX_WCHAR* pBuffer = wsDest.GetBuffer(nDestLen);
412  for (int32_t i = 0; i < nDestLen; i++) {
413    pBuffer[i] = bsReplace[i];
414  }
415  wsDest.ReleaseBuffer(nDestLen);
416  Replace(nWordStart, nWordCount, wsDest);
417  return TRUE;
418}
419void CFWL_EditImp::DrawSpellCheck(CFX_Graphics* pGraphics,
420                                  const CFX_Matrix* pMatrix) {
421  pGraphics->SaveGraphState();
422  if (pMatrix) {
423    pGraphics->ConcatMatrix(const_cast<CFX_Matrix*>(pMatrix));
424  }
425  FX_ARGB cr = 0xFFFF0000;
426  CFX_Color crLine(cr);
427  CFWL_EvtEdtCheckWord checkWordEvent;
428  checkWordEvent.m_pSrcTarget = m_pInterface;
429  CFX_ByteString sLatinWord;
430  CFX_Path pathSpell;
431  pathSpell.Create();
432  int32_t nStart = 0;
433  FX_FLOAT fOffSetX = m_rtEngine.left - m_fScrollOffsetX;
434  FX_FLOAT fOffSetY = m_rtEngine.top - m_fScrollOffsetY + m_fVAlignOffset;
435  CFX_WideString wsSpell;
436  this->GetText(wsSpell);
437  int32_t nContentLen = wsSpell.GetLength();
438  for (int i = 0; i < nContentLen; i++) {
439    if (FX_EDIT_ISLATINWORD(wsSpell[i])) {
440      if (sLatinWord.IsEmpty()) {
441        nStart = i;
442      }
443      sLatinWord += (FX_CHAR)wsSpell[i];
444    } else {
445      checkWordEvent.bsWord = sLatinWord;
446      checkWordEvent.bCheckWord = TRUE;
447      DispatchEvent(&checkWordEvent);
448      if (!sLatinWord.IsEmpty() && !checkWordEvent.bCheckWord) {
449        AddSpellCheckObj(pathSpell, nStart, sLatinWord.GetLength(), fOffSetX,
450                         fOffSetY);
451      }
452      sLatinWord.Empty();
453    }
454  }
455  checkWordEvent.bsWord = sLatinWord;
456  checkWordEvent.bCheckWord = TRUE;
457  DispatchEvent(&checkWordEvent);
458  if (!sLatinWord.IsEmpty() && !checkWordEvent.bCheckWord) {
459    AddSpellCheckObj(pathSpell, nStart, sLatinWord.GetLength(), fOffSetX,
460                     fOffSetY);
461  }
462  if (!pathSpell.IsEmpty()) {
463    CFX_RectF rtClip = m_rtEngine;
464    CFX_Matrix mt;
465    mt.Set(1, 0, 0, 1, fOffSetX, fOffSetY);
466    if (pMatrix) {
467      pMatrix->TransformRect(rtClip);
468      mt.Concat(*pMatrix);
469    }
470    pGraphics->SetClipRect(rtClip);
471    pGraphics->SetStrokeColor(&crLine);
472    pGraphics->SetLineWidth(0);
473    pGraphics->StrokePath(&pathSpell, NULL);
474  }
475  pGraphics->RestoreGraphState();
476}
477FWL_ERR CFWL_EditImp::DrawWidget(CFX_Graphics* pGraphics,
478                                 const CFX_Matrix* pMatrix) {
479  if (!pGraphics)
480    return FWL_ERR_Indefinite;
481  if (!m_pProperties->m_pThemeProvider)
482    return FWL_ERR_Indefinite;
483  if (m_rtClient.IsEmpty()) {
484    return FWL_ERR_Indefinite;
485  }
486  IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
487  if (!m_pWidgetMgr->IsFormDisabled()) {
488    DrawTextBk(pGraphics, pTheme, pMatrix);
489  }
490  if (m_pEdtEngine) {
491    DrawContent(pGraphics, pTheme, pMatrix);
492  }
493  if ((m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) &&
494      !(m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_ReadOnly)) {
495    DrawSpellCheck(pGraphics, pMatrix);
496  }
497  if (HasBorder()) {
498    DrawBorder(pGraphics, FWL_PART_EDT_Border, pTheme, pMatrix);
499  }
500  if (HasEdge()) {
501    DrawEdge(pGraphics, FWL_PART_EDT_Edge, pTheme, pMatrix);
502  }
503  return FWL_ERR_Succeeded;
504}
505FWL_ERR CFWL_EditImp::SetThemeProvider(IFWL_ThemeProvider* pThemeProvider) {
506  if (!pThemeProvider)
507    return FWL_ERR_Indefinite;
508  if (m_pHorzScrollBar) {
509    m_pHorzScrollBar->SetThemeProvider(pThemeProvider);
510  }
511  if (m_pVertScrollBar) {
512    m_pVertScrollBar->SetThemeProvider(pThemeProvider);
513  }
514  if (m_pCaret) {
515    m_pCaret->SetThemeProvider(pThemeProvider);
516  }
517  m_pProperties->m_pThemeProvider = pThemeProvider;
518  return FWL_ERR_Succeeded;
519}
520FWL_ERR CFWL_EditImp::SetText(const CFX_WideString& wsText) {
521  m_pEdtEngine->SetText(wsText);
522  return FWL_ERR_Succeeded;
523}
524int32_t CFWL_EditImp::GetTextLength() const {
525  if (!m_pEdtEngine)
526    return -1;
527  return m_pEdtEngine->GetTextLength();
528}
529FWL_ERR CFWL_EditImp::GetText(CFX_WideString& wsText,
530                              int32_t nStart,
531                              int32_t nCount) const {
532  if (!m_pEdtEngine)
533    return FWL_ERR_Succeeded;
534  m_pEdtEngine->GetText(wsText, nStart, nCount);
535  return FWL_ERR_Succeeded;
536}
537FWL_ERR CFWL_EditImp::ClearText() {
538  if (!m_pEdtEngine)
539    return FWL_ERR_Succeeded;
540  m_pEdtEngine->ClearText();
541  return FWL_ERR_Succeeded;
542}
543int32_t CFWL_EditImp::GetCaretPos() const {
544  if (!m_pEdtEngine)
545    return -1;
546  return m_pEdtEngine->GetCaretPos();
547}
548int32_t CFWL_EditImp::SetCaretPos(int32_t nIndex, FX_BOOL bBefore) {
549  if (!m_pEdtEngine)
550    return -1;
551  return m_pEdtEngine->SetCaretPos(nIndex, bBefore);
552}
553FWL_ERR CFWL_EditImp::AddSelRange(int32_t nStart, int32_t nCount) {
554  if (!m_pEdtEngine)
555    return FWL_ERR_Succeeded;
556  m_pEdtEngine->AddSelRange(nStart, nCount);
557  return FWL_ERR_Succeeded;
558}
559int32_t CFWL_EditImp::CountSelRanges() {
560  if (!m_pEdtEngine)
561    return 0;
562  return m_pEdtEngine->CountSelRanges();
563  return FWL_ERR_Succeeded;
564}
565int32_t CFWL_EditImp::GetSelRange(int32_t nIndex, int32_t& nStart) {
566  if (!m_pEdtEngine)
567    return -1;
568  return m_pEdtEngine->GetSelRange(nIndex, nStart);
569}
570FWL_ERR CFWL_EditImp::ClearSelections() {
571  if (!m_pEdtEngine)
572    return FWL_ERR_Succeeded;
573  m_pEdtEngine->ClearSelection();
574  return FWL_ERR_Succeeded;
575}
576int32_t CFWL_EditImp::GetLimit() {
577  return m_nLimit;
578}
579FWL_ERR CFWL_EditImp::SetLimit(int32_t nLimit) {
580  m_nLimit = nLimit;
581  if (!m_pEdtEngine)
582    return FWL_ERR_Succeeded;
583  m_pEdtEngine->SetLimit(nLimit);
584  return FWL_ERR_Succeeded;
585}
586FWL_ERR CFWL_EditImp::SetAliasChar(FX_WCHAR wAlias) {
587  if (!m_pEdtEngine)
588    return FWL_ERR_Indefinite;
589  m_pEdtEngine->SetAliasChar(wAlias);
590  return FWL_ERR_Succeeded;
591}
592FWL_ERR CFWL_EditImp::SetFormatString(const CFX_WideString& wsFormat) {
593  if (!m_pEdtEngine)
594    return FWL_ERR_Succeeded;
595  m_pEdtEngine->SetFormatBlock(0, wsFormat);
596  return FWL_ERR_Succeeded;
597}
598FWL_ERR CFWL_EditImp::Insert(int32_t nStart,
599                             const FX_WCHAR* lpText,
600                             int32_t nLen) {
601  if (!m_pEdtEngine)
602    return FWL_ERR_Succeeded;
603  if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_ReadOnly) ||
604      (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled)) {
605    return FWL_ERR_Indefinite;
606  }
607  m_pEdtEngine->Insert(nStart, lpText, nLen);
608  return FWL_ERR_Succeeded;
609}
610FWL_ERR CFWL_EditImp::DeleteSelections() {
611  if (!m_pEdtEngine)
612    return FWL_ERR_Succeeded;
613  int32_t iCount = m_pEdtEngine->CountSelRanges();
614  if (iCount > 0) {
615    m_pEdtEngine->Delete(-1);
616  }
617  return FWL_ERR_Succeeded;
618}
619FWL_ERR CFWL_EditImp::DeleteRange(int32_t nStart, int32_t nCount) {
620  if (!m_pEdtEngine)
621    return FWL_ERR_Succeeded;
622  m_pEdtEngine->DeleteRange(nStart, nCount);
623  return FWL_ERR_Succeeded;
624}
625FWL_ERR CFWL_EditImp::ReplaceSelections(const CFX_WideStringC& wsReplace) {
626  if (!m_pEdtEngine)
627    return FWL_ERR_Succeeded;
628  int32_t iCount = m_pEdtEngine->CountSelRanges();
629  for (int i = 0; i < iCount; i++) {
630    int32_t nStart;
631    int32_t nCount = m_pEdtEngine->GetSelRange(i, nStart);
632    m_pEdtEngine->Replace(nStart, nCount, wsReplace);
633  }
634  return FWL_ERR_Succeeded;
635}
636FWL_ERR CFWL_EditImp::Replace(int32_t nStart,
637                              int32_t nLen,
638                              const CFX_WideStringC& wsReplace) {
639  if (!m_pEdtEngine)
640    return FWL_ERR_Succeeded;
641  m_pEdtEngine->Replace(nStart, nLen, wsReplace);
642  return FWL_ERR_Succeeded;
643}
644FWL_ERR CFWL_EditImp::DoClipboard(int32_t iCmd) {
645  if (!m_pEdtEngine)
646    return FWL_ERR_Succeeded;
647  if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_ReadOnly) ||
648      (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled)) {
649    return FWL_ERR_Succeeded;
650  }
651  IFWL_AdapterNative* pNative = FWL_GetAdapterNative();
652  if (!pNative)
653    return FWL_ERR_Indefinite;
654  IFWL_AdapterClipboardMgr* pClipBorder = pNative->GetClipboardMgr();
655  if (!pClipBorder)
656    return FWL_ERR_Indefinite;
657  CFX_WideString wsText;
658  switch (iCmd) {
659    case 1: {
660      int32_t nStart;
661      int32_t nCount = m_pEdtEngine->GetSelRange(0, nStart);
662      if (nCount < 1) {
663        break;
664      }
665      m_pEdtEngine->GetText(wsText, nStart, nCount);
666      pClipBorder->SetStringData(wsText);
667      break;
668    }
669    case 2: {
670      int32_t nStart;
671      int32_t nCount = m_pEdtEngine->GetSelRange(0, nStart);
672      if (nCount < 1) {
673        break;
674      }
675      m_pEdtEngine->GetText(wsText, nStart, nCount);
676      m_pEdtEngine->DeleteRange(nStart, nCount);
677      m_pEdtEngine->ClearSelection();
678      pClipBorder->SetStringData(wsText);
679      break;
680    }
681    case 3: {
682      pClipBorder->GetStringData(wsText);
683      int32_t iLen = wsText.GetLength();
684      if (iLen < 0) {
685        break;
686      }
687      if (wsText[iLen] == L'\0') {
688        if (iLen == 1) {
689          break;
690        }
691        iLen--;
692        wsText = wsText.Left(iLen);
693      }
694      int32_t nPos = m_pEdtEngine->GetCaretPos();
695      m_pEdtEngine->Insert(nPos, wsText, iLen);
696      break;
697    }
698    default: {}
699  }
700  return FWL_ERR_Succeeded;
701}
702FX_BOOL CFWL_EditImp::Copy(CFX_WideString& wsCopy) {
703  if (!m_pEdtEngine)
704    return FALSE;
705  int32_t nCount = m_pEdtEngine->CountSelRanges();
706  if (nCount == 0) {
707    return FALSE;
708  }
709  wsCopy.Empty();
710  CFX_WideString wsTemp;
711  int32_t nStart, nLength;
712  for (int32_t i = 0; i < nCount; i++) {
713    nLength = m_pEdtEngine->GetSelRange(i, nStart);
714    m_pEdtEngine->GetText(wsTemp, nStart, nLength);
715    wsCopy += wsTemp;
716    wsTemp.Empty();
717  }
718  return TRUE;
719}
720FX_BOOL CFWL_EditImp::Cut(CFX_WideString& wsCut) {
721  if (!m_pEdtEngine)
722    return FALSE;
723  int32_t nCount = m_pEdtEngine->CountSelRanges();
724  if (nCount == 0) {
725    return FALSE;
726  }
727  wsCut.Empty();
728  CFX_WideString wsTemp;
729  int32_t nStart, nLength;
730  for (int32_t i = 0; i < nCount; i++) {
731    nLength = m_pEdtEngine->GetSelRange(i, nStart);
732    m_pEdtEngine->GetText(wsTemp, nStart, nLength);
733    wsCut += wsTemp;
734    wsTemp.Empty();
735  }
736  m_pEdtEngine->Delete(0);
737  return TRUE;
738}
739FX_BOOL CFWL_EditImp::Paste(const CFX_WideString& wsPaste) {
740  if (!m_pEdtEngine)
741    return FALSE;
742  int32_t nCaret = m_pEdtEngine->GetCaretPos();
743  int32_t iError =
744      m_pEdtEngine->Insert(nCaret, wsPaste.c_str(), wsPaste.GetLength());
745  if (iError < 0) {
746    ProcessInsertError(iError);
747    return FALSE;
748  }
749  return TRUE;
750}
751FX_BOOL CFWL_EditImp::Delete() {
752  if (!m_pEdtEngine)
753    return FALSE;
754  int32_t nCount = m_pEdtEngine->CountSelRanges();
755  if (nCount < 1) {
756    return FALSE;
757  }
758  m_pEdtEngine->Delete(0);
759  return TRUE;
760}
761FX_BOOL CFWL_EditImp::Redo(const CFX_ByteStringC& bsRecord) {
762  if (!m_pEdtEngine)
763    return FALSE;
764  if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_NoRedoUndo) {
765    return TRUE;
766  }
767  return m_pEdtEngine->Redo(bsRecord);
768}
769FX_BOOL CFWL_EditImp::Undo(const CFX_ByteStringC& bsRecord) {
770  if (!m_pEdtEngine)
771    return FALSE;
772  if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_NoRedoUndo) {
773    return TRUE;
774  }
775  return m_pEdtEngine->Undo(bsRecord);
776}
777FX_BOOL CFWL_EditImp::Undo() {
778  if (!CanUndo()) {
779    return FALSE;
780  }
781  CFX_ByteString bsRecord = m_RecordArr[m_iCurRecord--];
782  return Undo(bsRecord);
783}
784FX_BOOL CFWL_EditImp::Redo() {
785  if (!CanRedo()) {
786    return FALSE;
787  }
788  CFX_ByteString bsRecord = m_RecordArr[++m_iCurRecord];
789  return Redo(bsRecord);
790}
791FX_BOOL CFWL_EditImp::CanUndo() {
792  return m_iCurRecord >= 0;
793}
794FX_BOOL CFWL_EditImp::CanRedo() {
795  return m_iCurRecord < m_RecordArr.GetSize() - 1;
796}
797FWL_ERR CFWL_EditImp::SetTabWidth(FX_FLOAT fTabWidth, FX_BOOL bEquidistant) {
798  if (!m_pEdtEngine)
799    return FWL_ERR_Succeeded;
800  FDE_LPTXTEDTPARAMS pParams =
801      (FDE_LPTXTEDTPARAMS)m_pEdtEngine->GetEditParams();
802  pParams->fTabWidth = fTabWidth;
803  pParams->bTabEquidistant = bEquidistant;
804  return FWL_ERR_Succeeded;
805}
806FWL_ERR CFWL_EditImp::SetOuter(IFWL_Widget* pOuter) {
807  m_pOuter = pOuter;
808  return FWL_ERR_Succeeded;
809}
810FWL_ERR CFWL_EditImp::SetNumberRange(int32_t iMin, int32_t iMax) {
811  m_iMin = iMin;
812  m_iMax = iMax;
813  m_bSetRange = TRUE;
814  return FWL_ERR_Succeeded;
815}
816void CFWL_EditImp::On_CaretChanged(IFDE_TxtEdtEngine* pEdit,
817                                   int32_t nPage,
818                                   FX_BOOL bVisible) {
819  if (m_rtEngine.IsEmpty()) {
820    return;
821  }
822  if ((m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) == 0) {
823    return;
824  }
825  FX_BOOL bRepaintContent = UpdateOffset();
826  UpdateCaret();
827  CFX_RectF rtInvalid;
828  rtInvalid.Set(0, 0, 0, 0);
829  FX_BOOL bRepaintScroll = FALSE;
830  if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_MultiLine) {
831    IFWL_ScrollBar* pScroll = UpdateScroll();
832    if (pScroll) {
833      pScroll->GetWidgetRect(rtInvalid);
834      bRepaintScroll = TRUE;
835    }
836  }
837  if (bRepaintContent || bRepaintScroll) {
838    if (bRepaintContent) {
839      rtInvalid.Union(m_rtEngine);
840    }
841    Repaint(&rtInvalid);
842  }
843}
844void CFWL_EditImp::On_TextChanged(IFDE_TxtEdtEngine* pEdit,
845                                  FDE_TXTEDT_TEXTCHANGE_INFO& ChangeInfo) {
846  FX_DWORD dwStyleEx = m_pProperties->m_dwStyleExes;
847  if (dwStyleEx & FWL_STYLEEXT_EDT_VAlignMask) {
848    UpdateVAlignment();
849  }
850  IFDE_TxtEdtPage* page = m_pEdtEngine->GetPage(0);
851  FX_FLOAT fContentWidth = page->GetContentsBox().width;
852  FX_FLOAT fContentHeight = page->GetContentsBox().height;
853  CFX_RectF rtTemp;
854  GetClientRect(rtTemp);
855  FX_BOOL bHSelfAdaption =
856      m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_HSelfAdaption;
857  FX_BOOL bVSelfAdaption =
858      m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_VSelfAdaption;
859  FX_BOOL bNeedUpdate = FALSE;
860  if (bHSelfAdaption || bVSelfAdaption) {
861    CFWL_EvtEdtPreSelfAdaption evt;
862    evt.m_pSrcTarget = m_pInterface;
863    evt.bHSelfAdaption = TRUE;
864    evt.bVSelfAdaption = TRUE;
865    FX_FLOAT fWidth;
866    FX_FLOAT fHight;
867    fWidth = bHSelfAdaption ? fContentWidth : m_pProperties->m_rtWidget.width;
868    fHight = bVSelfAdaption ? fContentHeight : m_pProperties->m_rtWidget.height;
869    evt.rtAfterChange.Set(0, 0, fWidth, fHight);
870    DispatchEvent(&evt);
871    if (!evt.bHSelfAdaption) {
872      ModifyStylesEx(
873          0, FWL_STYLEEXT_EDT_HSelfAdaption | FWL_STYLEEXT_EDT_AutoHScroll);
874    }
875    if (!evt.bVSelfAdaption) {
876      ModifyStylesEx(
877          0, FWL_STYLEEXT_EDT_VSelfAdaption | FWL_STYLEEXT_EDT_AutoVScroll);
878    }
879    bNeedUpdate = (bHSelfAdaption && !evt.bHSelfAdaption) ||
880                  (bVSelfAdaption && !evt.bVSelfAdaption);
881  }
882  FX_FLOAT fContentWidth1 = fContentWidth;
883  FX_FLOAT fContentHeight1 = fContentHeight;
884  if (bNeedUpdate) {
885    UpdateEditParams();
886    UpdateEditLayout();
887    IFDE_TxtEdtPage* page1 = m_pEdtEngine->GetPage(0);
888    fContentWidth1 = page1->GetContentsBox().width;
889    fContentHeight1 = page1->GetContentsBox().height;
890  }
891  if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_HSelfAdaption) {
892    rtTemp.width = std::max(m_pProperties->m_rtWidget.width, fContentWidth1);
893    m_pProperties->m_rtWidget.width = fContentWidth1;
894  }
895  if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_VSelfAdaption) {
896    rtTemp.height = std::max(m_pProperties->m_rtWidget.height, fContentHeight1);
897    m_pProperties->m_rtWidget.height = fContentHeight1;
898  }
899  CFWL_EvtEdtTextChanged event;
900  event.m_pSrcTarget = m_pInterface;
901  event.nChangeType = ChangeInfo.nChangeType;
902  event.wsInsert = ChangeInfo.wsInsert;
903  event.wsDelete = ChangeInfo.wsDelete;
904  event.wsPrevText = ChangeInfo.wsPrevText;
905  DispatchEvent(&event);
906  LayoutScrollBar();
907  Repaint(&rtTemp);
908}
909void CFWL_EditImp::On_SelChanged(IFDE_TxtEdtEngine* pEdit) {
910  CFX_RectF rtTemp;
911  GetClientRect(rtTemp);
912  Repaint(&rtTemp);
913}
914FX_BOOL CFWL_EditImp::On_PageLoad(IFDE_TxtEdtEngine* pEdit,
915                                  int32_t nPageIndex,
916                                  int32_t nPurpose) {
917  IFDE_TxtEdtEngine* pEdtEngine = m_pEdtEngine;
918  IFDE_TxtEdtPage* pPage = pEdtEngine->GetPage(nPageIndex);
919  if (!pPage)
920    return FALSE;
921  pPage->LoadPage();
922  return TRUE;
923}
924FX_BOOL CFWL_EditImp::On_PageUnload(IFDE_TxtEdtEngine* pEdit,
925                                    int32_t nPageIndex,
926                                    int32_t nPurpose) {
927  IFDE_TxtEdtEngine* pEdtEngine = m_pEdtEngine;
928  IFDE_TxtEdtPage* pPage = pEdtEngine->GetPage(nPageIndex);
929  if (!pPage)
930    return FALSE;
931  pPage->UnloadPage();
932  return TRUE;
933}
934void CFWL_EditImp::On_AddDoRecord(IFDE_TxtEdtEngine* pEdit,
935                                  const CFX_ByteStringC& bsDoRecord) {
936  AddDoRecord(bsDoRecord);
937  CFWL_WidgetImp* pSrcTarget = GetRootOuter();
938  if (!pSrcTarget) {
939    pSrcTarget = this;
940  }
941  CFWL_EvtEdtAddDoRecord evt;
942  evt.m_pSrcTarget = m_pInterface;
943  evt.m_wsDoRecord = bsDoRecord;
944  m_pDelegate->OnProcessEvent(&evt);
945}
946FX_BOOL CFWL_EditImp::On_ValidateField(IFDE_TxtEdtEngine* pEdit,
947                                       int32_t nBlockIndex,
948                                       int32_t nFieldIndex,
949                                       const CFX_WideString& wsFieldText,
950                                       int32_t nCharIndex) {
951  return TRUE;
952}
953FX_BOOL CFWL_EditImp::On_ValidateBlock(IFDE_TxtEdtEngine* pEdit,
954                                       int32_t nBlockIndex) {
955  return TRUE;
956}
957FX_BOOL CFWL_EditImp::On_GetBlockFormatText(IFDE_TxtEdtEngine* pEdit,
958                                            int32_t nBlockIndex,
959                                            CFX_WideString& wsBlockText) {
960  return FALSE;
961}
962FX_BOOL CFWL_EditImp::On_Validate(IFDE_TxtEdtEngine* pEdit,
963                                  CFX_WideString& wsText) {
964  IFWL_Widget* pDst = GetOuter();
965  if (!pDst) {
966    pDst = m_pInterface;
967  }
968  CFWL_EvtEdtValidate event;
969  event.pDstWidget = pDst;
970  event.m_pSrcTarget = m_pInterface;
971  event.wsInsert = wsText;
972  event.bValidate = TRUE;
973  DispatchEvent(&event);
974  return event.bValidate;
975}
976FWL_ERR CFWL_EditImp::SetBackgroundColor(FX_DWORD color) {
977  m_backColor = color;
978  m_updateBackColor = TRUE;
979  return FWL_ERR_Succeeded;
980}
981FWL_ERR CFWL_EditImp::SetFont(const CFX_WideString& wsFont, FX_FLOAT fSize) {
982  m_wsFont = wsFont;
983  m_fFontSize = fSize;
984  return FWL_ERR_Succeeded;
985}
986void CFWL_EditImp::SetScrollOffset(FX_FLOAT fScrollOffset) {
987  m_fScrollOffsetY = fScrollOffset;
988}
989void CFWL_EditImp::DrawTextBk(CFX_Graphics* pGraphics,
990                              IFWL_ThemeProvider* pTheme,
991                              const CFX_Matrix* pMatrix) {
992  CFWL_ThemeBackground param;
993  param.m_pWidget = m_pInterface;
994  param.m_iPart = FWL_PART_EDT_Background;
995  param.m_dwData = FWL_PARTDATA_EDT_Background;
996  param.m_dwStates = m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_ReadOnly
997                         ? FWL_PARTSTATE_EDT_ReadOnly
998                         : FWL_PARTSTATE_EDT_Normal;
999  FX_DWORD dwStates = (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled);
1000  if (dwStates) {
1001    param.m_dwStates = FWL_PARTSTATE_EDT_Disable;
1002  }
1003  param.m_pGraphics = pGraphics;
1004  param.m_matrix = *pMatrix;
1005  param.m_rtPart = m_rtClient;
1006  pTheme->DrawBackground(&param);
1007  if (!IsShowScrollBar(TRUE) || !IsShowScrollBar(FALSE)) {
1008    return;
1009  }
1010  CFX_RectF rtScorll;
1011  m_pHorzScrollBar->GetWidgetRect(rtScorll);
1012  CFX_RectF rtStatic;
1013  rtStatic.Set(m_rtClient.right() - rtScorll.height,
1014               m_rtClient.bottom() - rtScorll.height, rtScorll.height,
1015               rtScorll.height);
1016  param.m_dwData = FWL_PARTDATA_EDT_StaticBackground;
1017  param.m_rtPart = rtStatic;
1018  pTheme->DrawBackground(&param);
1019}
1020void CFWL_EditImp::DrawContent(CFX_Graphics* pGraphics,
1021                               IFWL_ThemeProvider* pTheme,
1022                               const CFX_Matrix* pMatrix) {
1023  if (!m_pEdtEngine)
1024    return;
1025  IFDE_TxtEdtPage* pPage = m_pEdtEngine->GetPage(0);
1026  if (!pPage)
1027    return;
1028  pGraphics->SaveGraphState();
1029  if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_CombText) {
1030    pGraphics->SaveGraphState();
1031  }
1032  CFX_RectF rtClip = m_rtEngine;
1033  FX_FLOAT fOffSetX = m_rtEngine.left - m_fScrollOffsetX;
1034  FX_FLOAT fOffSetY = m_rtEngine.top - m_fScrollOffsetY + m_fVAlignOffset;
1035  CFX_Matrix mt;
1036  mt.Set(1, 0, 0, 1, fOffSetX, fOffSetY);
1037  if (pMatrix) {
1038    pMatrix->TransformRect(rtClip);
1039    mt.Concat(*pMatrix);
1040  }
1041  FX_BOOL bShowSel =
1042      (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_NoHideSel) ||
1043      (m_pProperties->m_dwStates & FWL_WGTSTATE_Focused);
1044  if (bShowSel) {
1045    IFWL_Widget* pForm =
1046        m_pWidgetMgr->GetWidget(m_pInterface, FWL_WGTRELATION_SystemForm);
1047    if (pForm) {
1048      bShowSel = (pForm->GetStates() & FWL_WGTSTATE_Deactivated) !=
1049                 FWL_WGTSTATE_Deactivated;
1050    }
1051  }
1052  int32_t nSelCount = m_pEdtEngine->CountSelRanges();
1053  if (bShowSel && nSelCount > 0) {
1054    int32_t nPageCharStart = pPage->GetCharStart();
1055    int32_t nPageCharCount = pPage->GetCharCount();
1056    int32_t nPageCharEnd = nPageCharStart + nPageCharCount - 1;
1057    int32_t nCharCount;
1058    int32_t nCharStart;
1059    CFX_RectFArray rectArr;
1060    int32_t i = 0;
1061    for (i = 0; i < nSelCount; i++) {
1062      nCharCount = m_pEdtEngine->GetSelRange(i, nCharStart);
1063      int32_t nCharEnd = nCharStart + nCharCount - 1;
1064      if (nCharEnd < nPageCharStart || nCharStart > nPageCharEnd) {
1065        continue;
1066      }
1067      int32_t nBgn = std::max(nCharStart, nPageCharStart);
1068      int32_t nEnd = std::min(nCharEnd, nPageCharEnd);
1069      pPage->CalcRangeRectArray(nBgn - nPageCharStart, nEnd - nBgn + 1,
1070                                rectArr);
1071    }
1072    int32_t nCount = rectArr.GetSize();
1073    CFX_Path path;
1074    path.Create();
1075    for (i = 0; i < nCount; i++) {
1076      rectArr[i].left += fOffSetX;
1077      rectArr[i].top += fOffSetY;
1078      path.AddRectangle(rectArr[i].left, rectArr[i].top, rectArr[i].width,
1079                        rectArr[i].height);
1080    }
1081    pGraphics->SetClipRect(rtClip);
1082    CFWL_ThemeBackground param;
1083    param.m_pGraphics = pGraphics;
1084    param.m_matrix = *pMatrix;
1085    param.m_pWidget = m_pInterface;
1086    param.m_iPart = FWL_PART_EDT_Background;
1087    param.m_pPath = &path;
1088    pTheme->DrawBackground(&param);
1089  }
1090  CFX_RenderDevice* pRenderDev = pGraphics->GetRenderDevice();
1091  if (!pRenderDev)
1092    return;
1093  IFDE_RenderDevice* pRenderDevice = IFDE_RenderDevice::Create(pRenderDev);
1094  if (!pRenderDevice)
1095    return;
1096  IFDE_RenderContext* pRenderContext = IFDE_RenderContext::Create();
1097  if (!pRenderContext)
1098    return;
1099  pRenderDevice->SetClipRect(rtClip);
1100  pRenderContext->StartRender(pRenderDevice, pPage, mt);
1101  pRenderContext->DoRender(NULL);
1102  pRenderContext->Release();
1103  pRenderDevice->Release();
1104  if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_CombText) {
1105    pGraphics->RestoreGraphState();
1106    CFX_Path path;
1107    path.Create();
1108    int32_t iLimit = m_nLimit > 0 ? m_nLimit : 1;
1109    FX_FLOAT fStep = m_rtEngine.width / iLimit;
1110    FX_FLOAT fLeft = m_rtEngine.left + 1;
1111    for (int32_t i = 1; i < iLimit; i++) {
1112      fLeft += fStep;
1113      path.AddLine(fLeft, m_rtClient.top, fLeft, m_rtClient.bottom());
1114    }
1115    CFWL_ThemeBackground param;
1116    param.m_pGraphics = pGraphics;
1117    param.m_matrix = *pMatrix;
1118    param.m_pWidget = m_pInterface;
1119    param.m_iPart = FWL_PART_EDT_CombTextLine;
1120    param.m_pPath = &path;
1121    pTheme->DrawBackground(&param);
1122  }
1123  pGraphics->RestoreGraphState();
1124}
1125void CFWL_EditImp::UpdateEditEngine() {
1126  UpdateEditParams();
1127  UpdateEditLayout();
1128  if (m_nLimit > -1) {
1129    m_pEdtEngine->SetLimit(m_nLimit);
1130  }
1131}
1132void CFWL_EditImp::UpdateEditParams() {
1133  FDE_TXTEDTPARAMS params;
1134  params.nHorzScale = 100;
1135  params.fPlateWidth = m_rtEngine.width;
1136  params.fPlateHeight = m_rtEngine.height;
1137  if (m_pProperties->m_dwStyles & FWL_WGTSTYLE_RTLLayout) {
1138    params.dwLayoutStyles |= FDE_TEXTEDITLAYOUT_RTL;
1139  }
1140  if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_VerticalLayout) {
1141    params.dwLayoutStyles |= FDE_TEXTEDITLAYOUT_DocVertical;
1142  }
1143  if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_VerticalChars) {
1144    params.dwLayoutStyles |= FDE_TEXTEDITLAYOUT_CharVertial;
1145  }
1146  if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_ReverseLine) {
1147    params.dwLayoutStyles |= FDE_TEXTEDITLAYOUT_LineReserve;
1148  }
1149  if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_ArabicShapes) {
1150    params.dwLayoutStyles |= FDE_TEXTEDITLAYOUT_ArabicShapes;
1151  }
1152  if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_ExpandTab) {
1153    params.dwLayoutStyles |= FDE_TEXTEDITLAYOUT_ExpandTab;
1154  }
1155  if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_CombText) {
1156    params.dwLayoutStyles |= FDE_TEXTEDITLAYOUT_CombText;
1157  }
1158  if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_LastLineHeight) {
1159    params.dwLayoutStyles |= FDE_TEXTEDITLAYOUT_LastLineHeight;
1160  }
1161  if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_Validate) {
1162    params.dwMode |= FDE_TEXTEDITMODE_Validate;
1163  }
1164  if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_Password) {
1165    params.dwMode |= FDE_TEXTEDITMODE_Password;
1166  }
1167  switch (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_HAlignMask) {
1168    case FWL_STYLEEXT_EDT_HNear: {
1169      params.dwAlignment |= FDE_TEXTEDITALIGN_Left;
1170      break;
1171    }
1172    case FWL_STYLEEXT_EDT_HCenter: {
1173      params.dwAlignment |= FDE_TEXTEDITALIGN_Center;
1174      break;
1175    }
1176    case FWL_STYLEEXT_EDT_HFar: {
1177      params.dwAlignment |= FDE_TEXTEDITALIGN_Right;
1178      break;
1179    }
1180    default: {}
1181  }
1182  switch (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_HAlignModeMask) {
1183    case FWL_STYLEEXT_EDT_Justified: {
1184      params.dwAlignment |= FDE_TEXTEDITALIGN_Justified;
1185      break;
1186    }
1187    case FWL_STYLEEXT_EDT_Distributed: {
1188      params.dwAlignment |= FDE_TEXTEDITALIGN_Distributed;
1189      break;
1190    }
1191    default: { params.dwAlignment |= FDE_TEXTEDITALIGN_Normal; }
1192  }
1193  if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_MultiLine) {
1194    params.dwMode |= FDE_TEXTEDITMODE_MultiLines;
1195    if ((m_pProperties->m_dwStyles & FWL_WGTSTYLE_HScroll) == 0 &&
1196        (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_AutoHScroll) == 0) {
1197      params.dwMode |=
1198          FDE_TEXTEDITMODE_AutoLineWrap | FDE_TEXTEDITMODE_LimitArea_Horz;
1199    }
1200    if ((m_pProperties->m_dwStyles & FWL_WGTSTYLE_VScroll) == 0 &&
1201        (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_AutoVScroll) == 0) {
1202      params.dwMode |= FDE_TEXTEDITMODE_LimitArea_Vert;
1203    } else {
1204      params.fPlateHeight = 0x00FFFFFF;
1205    }
1206  } else {
1207    if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_AutoHScroll) == 0) {
1208      params.dwMode |= FDE_TEXTEDITMODE_LimitArea_Horz;
1209    }
1210  }
1211  if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_ReadOnly) ||
1212      (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled)) {
1213    params.dwMode |= FDE_TEXTEDITMODE_ReadOnly;
1214  }
1215  FX_FLOAT* pFontSize =
1216      static_cast<FX_FLOAT*>(GetThemeCapacity(FWL_WGTCAPACITY_FontSize));
1217  if (!pFontSize)
1218    return;
1219  m_fFontSize = *pFontSize;
1220  FX_DWORD* pFontColor =
1221      static_cast<FX_DWORD*>(GetThemeCapacity(FWL_WGTCAPACITY_TextColor));
1222  if (!pFontColor)
1223    return;
1224  params.dwFontColor = *pFontColor;
1225  FX_FLOAT* pLineHeight =
1226      static_cast<FX_FLOAT*>(GetThemeCapacity(FWL_WGTCAPACITY_LineHeight));
1227  if (!pLineHeight)
1228    return;
1229  params.fLineSpace = *pLineHeight;
1230  IFX_Font* pFont =
1231      static_cast<IFX_Font*>(GetThemeCapacity(FWL_WGTCAPACITY_Font));
1232  if (!pFont)
1233    return;
1234  params.pFont = pFont;
1235  params.fFontSize = m_fFontSize;
1236  params.nLineCount = (int32_t)(params.fPlateHeight / params.fLineSpace);
1237  if (params.nLineCount <= 0) {
1238    params.nLineCount = 1;
1239  }
1240  params.fTabWidth = params.fFontSize * 1;
1241  params.bTabEquidistant = TRUE;
1242  params.wLineBreakChar = L'\n';
1243  params.nCharRotation = 0;
1244  params.pEventSink = this;
1245  m_pEdtEngine->SetEditParams(params);
1246}
1247void CFWL_EditImp::UpdateEditLayout() {
1248  if (m_pEdtEngine->GetTextLength() <= 0) {
1249    m_pEdtEngine->SetTextByStream(NULL);
1250  }
1251  IFDE_TxtEdtPage* pPage = m_pEdtEngine->GetPage(0);
1252  if (pPage) {
1253    pPage->UnloadPage();
1254    pPage = NULL;
1255  }
1256  m_pEdtEngine->StartLayout();
1257  m_pEdtEngine->DoLayout(NULL);
1258  m_pEdtEngine->EndLayout();
1259  pPage = m_pEdtEngine->GetPage(0);
1260  if (pPage) {
1261    pPage->LoadPage();
1262  }
1263}
1264FX_BOOL CFWL_EditImp::UpdateOffset() {
1265  CFX_RectF rtCaret;
1266  m_pEdtEngine->GetCaretRect(rtCaret);
1267  FX_FLOAT fOffSetX = m_rtEngine.left - m_fScrollOffsetX;
1268  FX_FLOAT fOffSetY = m_rtEngine.top - m_fScrollOffsetY + m_fVAlignOffset;
1269  rtCaret.Offset(fOffSetX, fOffSetY);
1270  const CFX_RectF& rtEidt = m_rtEngine;
1271  if (rtEidt.Contains(rtCaret)) {
1272    IFDE_TxtEdtPage* pPage = m_pEdtEngine->GetPage(0);
1273    if (!pPage)
1274      return FALSE;
1275    CFX_RectF rtFDE = pPage->GetContentsBox();
1276    rtFDE.Offset(fOffSetX, fOffSetY);
1277    if (rtFDE.right() < rtEidt.right() && m_fScrollOffsetX > 0) {
1278      m_fScrollOffsetX += rtFDE.right() - rtEidt.right();
1279      if (m_fScrollOffsetX < 0) {
1280        m_fScrollOffsetX = 0;
1281      }
1282    }
1283    if (rtFDE.bottom() < rtEidt.bottom() && m_fScrollOffsetY > 0) {
1284      m_fScrollOffsetY += rtFDE.bottom() - rtEidt.bottom();
1285      if (m_fScrollOffsetY < 0) {
1286        m_fScrollOffsetY = 0;
1287      }
1288    }
1289    return FALSE;
1290  } else {
1291    FX_FLOAT offsetX = 0.0;
1292    FX_FLOAT offsetY = 0.0;
1293    if (rtCaret.left < rtEidt.left) {
1294      offsetX = rtCaret.left - rtEidt.left;
1295    }
1296    if (rtCaret.right() > rtEidt.right()) {
1297      offsetX = rtCaret.right() - rtEidt.right();
1298    }
1299    if (rtCaret.top < rtEidt.top) {
1300      offsetY = rtCaret.top - rtEidt.top;
1301    }
1302    if (rtCaret.bottom() > rtEidt.bottom()) {
1303      offsetY = rtCaret.bottom() - rtEidt.bottom();
1304    }
1305    if (!(m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_HSelfAdaption)) {
1306      m_fScrollOffsetX += offsetX;
1307    }
1308    if (!(m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_VSelfAdaption)) {
1309      m_fScrollOffsetY += offsetY;
1310    }
1311    if (m_fFontSize > m_rtEngine.height) {
1312      m_fScrollOffsetY = 0;
1313    }
1314    return TRUE;
1315  }
1316}
1317FX_BOOL CFWL_EditImp::UpdateOffset(IFWL_ScrollBar* pScrollBar,
1318                                   FX_FLOAT fPosChanged) {
1319  if (pScrollBar == m_pHorzScrollBar.get()) {
1320    m_fScrollOffsetX += fPosChanged;
1321  } else {
1322    m_fScrollOffsetY += fPosChanged;
1323  }
1324  return TRUE;
1325}
1326void CFWL_EditImp::UpdateVAlignment() {
1327  IFDE_TxtEdtPage* pPage = m_pEdtEngine->GetPage(0);
1328  if (!pPage)
1329    return;
1330  const CFX_RectF& rtFDE = pPage->GetContentsBox();
1331  FX_FLOAT fOffsetY = 0.0f;
1332  FX_FLOAT fSpaceAbove = 0.0f;
1333  FX_FLOAT fSpaceBelow = 0.0f;
1334  CFX_SizeF* pSpace = static_cast<CFX_SizeF*>(
1335      GetThemeCapacity(FWL_WGTCAPACITY_SpaceAboveBelow));
1336  if (pSpace) {
1337    fSpaceAbove = pSpace->x;
1338    fSpaceBelow = pSpace->y;
1339  }
1340  if (fSpaceAbove < 0.1f) {
1341    fSpaceAbove = 0;
1342  }
1343  if (fSpaceBelow < 0.1f) {
1344    fSpaceBelow = 0;
1345  }
1346  if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_VCenter) {
1347    fOffsetY = (m_rtEngine.height - rtFDE.height) / 2;
1348    if (fOffsetY < (fSpaceAbove + fSpaceBelow) / 2 &&
1349        fSpaceAbove < fSpaceBelow) {
1350      return;
1351    }
1352    fOffsetY += (fSpaceAbove - fSpaceBelow) / 2;
1353  } else if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_VFar) {
1354    fOffsetY = (m_rtEngine.height - rtFDE.height);
1355    fOffsetY -= fSpaceBelow;
1356  } else {
1357    fOffsetY += fSpaceAbove;
1358  }
1359  m_fVAlignOffset = fOffsetY;
1360  if (m_fVAlignOffset < 0) {
1361    m_fVAlignOffset = 0;
1362  }
1363}
1364void CFWL_EditImp::UpdateCaret() {
1365  CFX_RectF rtFDE;
1366  m_pEdtEngine->GetCaretRect(rtFDE);
1367  rtFDE.Offset(m_rtEngine.left - m_fScrollOffsetX,
1368               m_rtEngine.top - m_fScrollOffsetY + m_fVAlignOffset);
1369  CFX_RectF rtCaret;
1370  rtCaret.Set(rtFDE.left, rtFDE.top, rtFDE.width, rtFDE.height);
1371  CFX_RectF temp = rtCaret;
1372  CFX_RectF rtClient;
1373  GetClientRect(rtClient);
1374  rtCaret.Intersect(rtClient);
1375  if (rtCaret.left > rtClient.right()) {
1376    FX_FLOAT right = rtCaret.right();
1377    rtCaret.left = rtClient.right() - 1;
1378    rtCaret.width = right - rtCaret.left;
1379  }
1380  FX_BOOL bIntersect = !rtCaret.IsEmpty();
1381  FX_BOOL bShow = TRUE;
1382  FX_BOOL bShowWhole = FALSE;
1383  if (!(m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) || !bIntersect) {
1384    bShow = FALSE;
1385  }
1386  if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_HSelfAdaption &&
1387      temp.right() > m_rtEngine.right()) {
1388    bShowWhole = TRUE;
1389  }
1390  if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_VSelfAdaption &&
1391      temp.bottom() > m_rtEngine.bottom()) {
1392    bShowWhole = TRUE;
1393  } else {
1394    bShow = (m_pProperties->m_dwStates & FWL_WGTSTATE_Focused && bIntersect);
1395  }
1396  if (bShowWhole) {
1397    rtCaret = temp;
1398  }
1399  ShowCaret(bShow, &rtCaret);
1400}
1401IFWL_ScrollBar* CFWL_EditImp::UpdateScroll() {
1402  FX_BOOL bShowHorz =
1403      m_pHorzScrollBar &&
1404      ((m_pHorzScrollBar->GetStates() & FWL_WGTSTATE_Invisible) == 0);
1405  FX_BOOL bShowVert =
1406      m_pVertScrollBar &&
1407      ((m_pVertScrollBar->GetStates() & FWL_WGTSTATE_Invisible) == 0);
1408  if (!bShowHorz && !bShowVert) {
1409    return NULL;
1410  }
1411  IFDE_TxtEdtPage* pPage = m_pEdtEngine->GetPage(0);
1412  if (!pPage)
1413    return NULL;
1414  const CFX_RectF& rtFDE = pPage->GetContentsBox();
1415  IFWL_ScrollBar* pRepaint = NULL;
1416  if (bShowHorz) {
1417    CFX_RectF rtScroll;
1418    m_pHorzScrollBar->GetWidgetRect(rtScroll);
1419    if (rtScroll.width < rtFDE.width) {
1420      m_pHorzScrollBar->LockUpdate();
1421      FX_FLOAT fRange = rtFDE.width - rtScroll.width;
1422      m_pHorzScrollBar->SetRange(0.0f, fRange);
1423      FX_FLOAT fPos = m_fScrollOffsetX;
1424      if (fPos < 0.0f) {
1425        fPos = 0.0f;
1426      }
1427      if (fPos > fRange) {
1428        fPos = fRange;
1429      }
1430      m_pHorzScrollBar->SetPos(fPos);
1431      m_pHorzScrollBar->SetTrackPos(fPos);
1432      m_pHorzScrollBar->SetPageSize(rtScroll.width);
1433      m_pHorzScrollBar->SetStepSize(rtScroll.width / 10);
1434      m_pHorzScrollBar->SetStates(FWL_WGTSTATE_Disabled, FALSE);
1435      m_pHorzScrollBar->UnlockUpdate();
1436      m_pHorzScrollBar->Update();
1437      pRepaint = m_pHorzScrollBar.get();
1438    } else if ((m_pHorzScrollBar->GetStates() & FWL_WGTSTATE_Disabled) == 0) {
1439      m_pHorzScrollBar->LockUpdate();
1440      m_pHorzScrollBar->SetRange(0, -1);
1441      m_pHorzScrollBar->SetStates(FWL_WGTSTATE_Disabled, TRUE);
1442      m_pHorzScrollBar->UnlockUpdate();
1443      m_pHorzScrollBar->Update();
1444      pRepaint = m_pHorzScrollBar.get();
1445    }
1446  }
1447  if (bShowVert) {
1448    CFX_RectF rtScroll;
1449    m_pVertScrollBar->GetWidgetRect(rtScroll);
1450    if (rtScroll.height < rtFDE.height) {
1451      m_pVertScrollBar->LockUpdate();
1452      FX_FLOAT fStep = m_pEdtEngine->GetEditParams()->fLineSpace;
1453      FX_FLOAT fRange = rtFDE.height - m_rtEngine.height;
1454      if (fRange < fStep) {
1455        fRange = fStep;
1456      }
1457      m_pVertScrollBar->SetRange(0.0f, fRange);
1458      FX_FLOAT fPos = m_fScrollOffsetY;
1459      if (fPos < 0.0f) {
1460        fPos = 0.0f;
1461      }
1462      if (fPos > fRange) {
1463        fPos = fRange;
1464      }
1465      m_pVertScrollBar->SetPos(fPos);
1466      m_pVertScrollBar->SetTrackPos(fPos);
1467      m_pVertScrollBar->SetPageSize(rtScroll.height);
1468      m_pVertScrollBar->SetStepSize(fStep);
1469      m_pVertScrollBar->SetStates(FWL_WGTSTATE_Disabled, FALSE);
1470      m_pVertScrollBar->UnlockUpdate();
1471      m_pVertScrollBar->Update();
1472      pRepaint = m_pVertScrollBar.get();
1473    } else if ((m_pVertScrollBar->GetStates() & FWL_WGTSTATE_Disabled) == 0) {
1474      m_pVertScrollBar->LockUpdate();
1475      m_pVertScrollBar->SetRange(0, -1);
1476      m_pVertScrollBar->SetStates(FWL_WGTSTATE_Disabled, TRUE);
1477      m_pVertScrollBar->UnlockUpdate();
1478      m_pVertScrollBar->Update();
1479      pRepaint = m_pVertScrollBar.get();
1480    }
1481  }
1482  return pRepaint;
1483}
1484FX_BOOL CFWL_EditImp::IsShowScrollBar(FX_BOOL bVert) {
1485  FX_BOOL bShow =
1486      (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_ShowScrollbarFocus)
1487          ? (m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) ==
1488                FWL_WGTSTATE_Focused
1489          : TRUE;
1490  if (bVert) {
1491    return bShow && (m_pProperties->m_dwStyles & FWL_WGTSTYLE_VScroll) &&
1492           (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_MultiLine) &&
1493           IsContentHeightOverflow();
1494  }
1495  return bShow && (m_pProperties->m_dwStyles & FWL_WGTSTYLE_HScroll) &&
1496         (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_MultiLine);
1497}
1498FX_BOOL CFWL_EditImp::IsContentHeightOverflow() {
1499  if (!m_pEdtEngine)
1500    return FALSE;
1501  IFDE_TxtEdtPage* pPage = m_pEdtEngine->GetPage(0);
1502  if (!pPage)
1503    return FALSE;
1504  return pPage->GetContentsBox().height > m_rtEngine.height + 1.0f;
1505}
1506int32_t CFWL_EditImp::AddDoRecord(const CFX_ByteStringC& bsDoRecord) {
1507  int32_t nCount = m_RecordArr.GetSize();
1508  if (m_iCurRecord == nCount - 1) {
1509    if (nCount == m_iMaxRecord) {
1510      m_RecordArr.RemoveAt(0);
1511      m_iCurRecord--;
1512    }
1513  } else {
1514    for (int32_t i = nCount - 1; i > m_iCurRecord; i--) {
1515      m_RecordArr.RemoveAt(i);
1516    }
1517  }
1518  m_RecordArr.Add(bsDoRecord);
1519  return m_iCurRecord = m_RecordArr.GetSize() - 1;
1520}
1521void CFWL_EditImp::Layout() {
1522  GetClientRect(m_rtClient);
1523  m_rtEngine = m_rtClient;
1524  FX_FLOAT* pfWidth =
1525      static_cast<FX_FLOAT*>(GetThemeCapacity(FWL_WGTCAPACITY_ScrollBarWidth));
1526  if (!pfWidth)
1527    return;
1528  FX_FLOAT fWidth = *pfWidth;
1529  if (!m_pOuter) {
1530    CFX_RectF* pUIMargin =
1531        static_cast<CFX_RectF*>(GetThemeCapacity(FWL_WGTCAPACITY_UIMargin));
1532    if (pUIMargin) {
1533      m_rtEngine.Deflate(pUIMargin->left, pUIMargin->top, pUIMargin->width,
1534                         pUIMargin->height);
1535    }
1536  } else if (m_pOuter->GetClassID() == FWL_CLASSHASH_DateTimePicker) {
1537    CFWL_ThemePart part;
1538    part.m_pWidget = m_pOuter;
1539    CFX_RectF* pUIMargin =
1540        static_cast<CFX_RectF*>(m_pOuter->GetThemeProvider()->GetCapacity(
1541            &part, FWL_WGTCAPACITY_UIMargin));
1542    if (pUIMargin) {
1543      m_rtEngine.Deflate(pUIMargin->left, pUIMargin->top, pUIMargin->width,
1544                         pUIMargin->height);
1545    }
1546  }
1547  FX_BOOL bShowVertScrollbar = IsShowScrollBar(TRUE);
1548  FX_BOOL bShowHorzScrollbar = IsShowScrollBar(FALSE);
1549  if (bShowVertScrollbar) {
1550    InitScrollBar();
1551    CFX_RectF rtVertScr;
1552    if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_OuterScrollbar) {
1553      rtVertScr.Set(m_rtClient.right() + FWL_EDIT_Margin, m_rtClient.top,
1554                    fWidth, m_rtClient.height);
1555    } else {
1556      rtVertScr.Set(m_rtClient.right() - fWidth, m_rtClient.top, fWidth,
1557                    m_rtClient.height);
1558      if (bShowHorzScrollbar) {
1559        rtVertScr.height -= fWidth;
1560      }
1561      m_rtEngine.width -= fWidth;
1562    }
1563    m_pVertScrollBar->SetWidgetRect(rtVertScr);
1564    m_pVertScrollBar->SetStates(FWL_WGTSTATE_Invisible, FALSE);
1565    m_pVertScrollBar->Update();
1566  } else if (m_pVertScrollBar) {
1567    m_pVertScrollBar->SetStates(FWL_WGTSTATE_Invisible, TRUE);
1568  }
1569  if (bShowHorzScrollbar) {
1570    InitScrollBar(FALSE);
1571    CFX_RectF rtHoriScr;
1572    if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_OuterScrollbar) {
1573      rtHoriScr.Set(m_rtClient.left, m_rtClient.bottom() + FWL_EDIT_Margin,
1574                    m_rtClient.width, fWidth);
1575    } else {
1576      rtHoriScr.Set(m_rtClient.left, m_rtClient.bottom() - fWidth,
1577                    m_rtClient.width, fWidth);
1578      if (bShowVertScrollbar) {
1579        rtHoriScr.width -= fWidth;
1580      }
1581      m_rtEngine.height -= fWidth;
1582    }
1583    m_pHorzScrollBar->SetWidgetRect(rtHoriScr);
1584    m_pHorzScrollBar->SetStates(FWL_WGTSTATE_Invisible, FALSE);
1585    m_pHorzScrollBar->Update();
1586  } else if (m_pHorzScrollBar) {
1587    m_pHorzScrollBar->SetStates(FWL_WGTSTATE_Invisible, TRUE);
1588  }
1589}
1590void CFWL_EditImp::LayoutScrollBar() {
1591  if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_ShowScrollbarFocus) ==
1592      0) {
1593    return;
1594  }
1595  FX_FLOAT* pfWidth = NULL;
1596  FX_BOOL bShowVertScrollbar = IsShowScrollBar(TRUE);
1597  FX_BOOL bShowHorzScrollbar = IsShowScrollBar(FALSE);
1598  if (bShowVertScrollbar) {
1599    if (!m_pVertScrollBar) {
1600      pfWidth = static_cast<FX_FLOAT*>(
1601          GetThemeCapacity(FWL_WGTCAPACITY_ScrollBarWidth));
1602      FX_FLOAT fWidth = pfWidth ? *pfWidth : 0;
1603      InitScrollBar();
1604      CFX_RectF rtVertScr;
1605      if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_OuterScrollbar) {
1606        rtVertScr.Set(m_rtClient.right() + FWL_EDIT_Margin, m_rtClient.top,
1607                      fWidth, m_rtClient.height);
1608      } else {
1609        rtVertScr.Set(m_rtClient.right() - fWidth, m_rtClient.top, fWidth,
1610                      m_rtClient.height);
1611        if (bShowHorzScrollbar) {
1612          rtVertScr.height -= fWidth;
1613        }
1614      }
1615      m_pVertScrollBar->SetWidgetRect(rtVertScr);
1616      m_pVertScrollBar->Update();
1617    }
1618    m_pVertScrollBar->SetStates(FWL_WGTSTATE_Invisible, FALSE);
1619  } else if (m_pVertScrollBar) {
1620    m_pVertScrollBar->SetStates(FWL_WGTSTATE_Invisible, TRUE);
1621  }
1622  if (bShowHorzScrollbar) {
1623    if (!m_pHorzScrollBar) {
1624      if (!pfWidth) {
1625        pfWidth = static_cast<FX_FLOAT*>(
1626            GetThemeCapacity(FWL_WGTCAPACITY_ScrollBarWidth));
1627      }
1628      FX_FLOAT fWidth = pfWidth ? *pfWidth : 0;
1629      InitScrollBar(FALSE);
1630      CFX_RectF rtHoriScr;
1631      if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_OuterScrollbar) {
1632        rtHoriScr.Set(m_rtClient.left, m_rtClient.bottom() + FWL_EDIT_Margin,
1633                      m_rtClient.width, fWidth);
1634      } else {
1635        rtHoriScr.Set(m_rtClient.left, m_rtClient.bottom() - fWidth,
1636                      m_rtClient.width, fWidth);
1637        if (bShowVertScrollbar) {
1638          rtHoriScr.width -= (fWidth);
1639        }
1640      }
1641      m_pHorzScrollBar->SetWidgetRect(rtHoriScr);
1642      m_pHorzScrollBar->Update();
1643    }
1644    m_pHorzScrollBar->SetStates(FWL_WGTSTATE_Invisible, FALSE);
1645  } else if (m_pHorzScrollBar) {
1646    m_pHorzScrollBar->SetStates(FWL_WGTSTATE_Invisible, TRUE);
1647  }
1648  if (bShowVertScrollbar || bShowHorzScrollbar) {
1649    UpdateScroll();
1650  }
1651}
1652void CFWL_EditImp::DeviceToEngine(CFX_PointF& pt) {
1653  pt.x += -m_rtEngine.left + m_fScrollOffsetX;
1654  pt.y += -m_rtEngine.top - m_fVAlignOffset + m_fScrollOffsetY;
1655}
1656void CFWL_EditImp::InitScrollBar(FX_BOOL bVert) {
1657  if ((bVert && m_pVertScrollBar) || (!bVert && m_pHorzScrollBar)) {
1658    return;
1659  }
1660  CFWL_WidgetImpProperties prop;
1661  prop.m_dwStyleExes = bVert ? FWL_STYLEEXT_SCB_Vert : FWL_STYLEEXT_SCB_Horz;
1662  prop.m_dwStates = FWL_WGTSTATE_Disabled | FWL_WGTSTATE_Invisible;
1663  prop.m_pParent = m_pInterface;
1664  prop.m_pThemeProvider = m_pProperties->m_pThemeProvider;
1665  IFWL_ScrollBar* pScrollBar = IFWL_ScrollBar::Create(prop, m_pInterface);
1666  pScrollBar->Initialize();
1667  (bVert ? &m_pVertScrollBar : &m_pHorzScrollBar)->reset(pScrollBar);
1668}
1669void CFWL_EditImp::InitEngine() {
1670  if (m_pEdtEngine) {
1671    return;
1672  }
1673  m_pEdtEngine = IFDE_TxtEdtEngine::Create();
1674}
1675extern FX_BOOL FWL_ShowCaret(IFWL_Widget* pWidget,
1676                             FX_BOOL bVisible,
1677                             const CFX_RectF* pRtAnchor);
1678void CFWL_EditImp::ShowCaret(FX_BOOL bVisible, CFX_RectF* pRect) {
1679  if (m_pCaret) {
1680    m_pCaret->ShowCaret(bVisible);
1681    if (bVisible && !pRect->IsEmpty()) {
1682      m_pCaret->SetWidgetRect(*pRect);
1683    }
1684    Repaint(&m_rtEngine);
1685  } else {
1686    IFWL_Widget* pOuter = m_pInterface;
1687    if (bVisible) {
1688      pRect->Offset(m_pProperties->m_rtWidget.left,
1689                    m_pProperties->m_rtWidget.top);
1690    }
1691    while (pOuter->GetOuter()) {
1692      pOuter = pOuter->GetOuter();
1693      if (bVisible) {
1694        CFX_RectF rtOuter;
1695        pOuter->GetWidgetRect(rtOuter);
1696        pRect->Offset(rtOuter.left, rtOuter.top);
1697      }
1698    }
1699    FWL_ShowCaret(pOuter, bVisible, pRect);
1700  }
1701}
1702FX_BOOL CFWL_EditImp::ValidateNumberChar(FX_WCHAR cNum) {
1703  if (!m_pEdtEngine) {
1704    return FALSE;
1705  }
1706  if (!m_bSetRange) {
1707    return TRUE;
1708  }
1709  CFX_WideString wsOld, wsText;
1710  m_pEdtEngine->GetText(wsText, 0);
1711  if (wsText.IsEmpty()) {
1712    if (cNum == L'0') {
1713      return FALSE;
1714    }
1715    return TRUE;
1716  }
1717  int32_t caretPos = m_pEdtEngine->GetCaretPos();
1718  int32_t iSel = CountSelRanges();
1719  if (iSel == 0) {
1720    if (cNum == L'0' && caretPos == 0) {
1721      return FALSE;
1722    }
1723    int32_t nLen = wsText.GetLength();
1724    CFX_WideString l = wsText.Mid(0, caretPos);
1725    CFX_WideString r = wsText.Mid(caretPos, nLen - caretPos);
1726    CFX_WideString wsNew = l + cNum + r;
1727    if (wsNew.GetInteger() <= m_iMax) {
1728      return TRUE;
1729    }
1730  } else {
1731    if (wsText.GetInteger() <= m_iMax) {
1732      return TRUE;
1733    }
1734  }
1735  return FALSE;
1736}
1737void CFWL_EditImp::InitCaret() {
1738  if (!m_pCaret) {
1739    if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_InnerCaret)) {
1740      CFWL_WidgetImpProperties prop;
1741      m_pCaret.reset(IFWL_Caret::Create(prop, m_pInterface));
1742      m_pCaret->Initialize();
1743      m_pCaret->SetParent(m_pInterface);
1744      m_pCaret->SetStates(m_pProperties->m_dwStates);
1745    }
1746  } else if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_InnerCaret) ==
1747             0) {
1748    m_pCaret.reset();
1749  }
1750}
1751void CFWL_EditImp::ClearRecord() {
1752  m_iCurRecord = -1;
1753  m_RecordArr.RemoveAll();
1754}
1755void CFWL_EditImp::ProcessInsertError(int32_t iError) {
1756  switch (iError) {
1757    case -2: {
1758      CFWL_EvtEdtTextFull textFullEvent;
1759      textFullEvent.m_pSrcTarget = m_pInterface;
1760      DispatchEvent(&textFullEvent);
1761      break;
1762    }
1763    default: {}
1764  }
1765}
1766CFWL_EditImpDelegate::CFWL_EditImpDelegate(CFWL_EditImp* pOwner)
1767    : m_pOwner(pOwner) {}
1768int32_t CFWL_EditImpDelegate::OnProcessMessage(CFWL_Message* pMessage) {
1769  if (!pMessage)
1770    return 0;
1771  FX_DWORD dwMsgCode = pMessage->GetClassID();
1772  int32_t iRet = 1;
1773  switch (dwMsgCode) {
1774    case FWL_MSGHASH_Activate: {
1775      DoActivate(static_cast<CFWL_MsgActivate*>(pMessage));
1776      break;
1777    }
1778    case FWL_MSGHASH_Deactivate: {
1779      DoDeactivate(static_cast<CFWL_MsgDeactivate*>(pMessage));
1780      break;
1781    }
1782    case FWL_MSGHASH_SetFocus:
1783    case FWL_MSGHASH_KillFocus: {
1784      OnFocusChanged(pMessage, dwMsgCode == FWL_MSGHASH_SetFocus);
1785      break;
1786    }
1787    case FWL_MSGHASH_Mouse: {
1788      CFWL_MsgMouse* pMsg = static_cast<CFWL_MsgMouse*>(pMessage);
1789      FX_DWORD dwCmd = pMsg->m_dwCmd;
1790      switch (dwCmd) {
1791        case FWL_MSGMOUSECMD_LButtonDown: {
1792          OnLButtonDown(pMsg);
1793          break;
1794        }
1795        case FWL_MSGMOUSECMD_LButtonUp: {
1796          OnLButtonUp(pMsg);
1797          break;
1798        }
1799        case FWL_MSGMOUSECMD_LButtonDblClk: {
1800          OnButtonDblClk(pMsg);
1801          break;
1802        }
1803        case FWL_MSGMOUSECMD_MouseMove: {
1804          OnMouseMove(pMsg);
1805          break;
1806        }
1807        case FWL_MSGMOUSECMD_RButtonDown: {
1808          DoButtonDown(pMsg);
1809          break;
1810        }
1811        default: {}
1812      }
1813      break;
1814    }
1815    case FWL_MSGHASH_Key: {
1816      CFWL_MsgKey* pKey = static_cast<CFWL_MsgKey*>(pMessage);
1817      FX_DWORD dwCmd = pKey->m_dwCmd;
1818      if (dwCmd == FWL_MSGKEYCMD_KeyDown) {
1819        OnKeyDown(pKey);
1820      } else if (dwCmd == FWL_MSGKEYCMD_Char) {
1821        OnChar(pKey);
1822      }
1823      break;
1824    }
1825    default: { iRet = 0; }
1826  }
1827  CFWL_WidgetImpDelegate::OnProcessMessage(pMessage);
1828  return iRet;
1829}
1830FWL_ERR CFWL_EditImpDelegate::OnProcessEvent(CFWL_Event* pEvent) {
1831  if (!pEvent)
1832    return FWL_ERR_Indefinite;
1833  FX_DWORD dwHashCode = pEvent->GetClassID();
1834  if (dwHashCode != FWL_EVTHASH_Scroll) {
1835    return FWL_ERR_Succeeded;
1836  }
1837  IFWL_Widget* pSrcTarget = pEvent->m_pSrcTarget;
1838  if ((pSrcTarget == m_pOwner->m_pVertScrollBar.get() &&
1839       m_pOwner->m_pVertScrollBar) ||
1840      (pSrcTarget == m_pOwner->m_pHorzScrollBar.get() &&
1841       m_pOwner->m_pHorzScrollBar)) {
1842    CFWL_EvtScroll* pScrollEvent = static_cast<CFWL_EvtScroll*>(pEvent);
1843    OnScroll(static_cast<IFWL_ScrollBar*>(pSrcTarget),
1844             pScrollEvent->m_iScrollCode, pScrollEvent->m_fPos);
1845  }
1846  return FWL_ERR_Succeeded;
1847}
1848FWL_ERR CFWL_EditImpDelegate::OnDrawWidget(CFX_Graphics* pGraphics,
1849                                           const CFX_Matrix* pMatrix) {
1850  return m_pOwner->DrawWidget(pGraphics, pMatrix);
1851}
1852void CFWL_EditImpDelegate::DoActivate(CFWL_MsgActivate* pMsg) {
1853  m_pOwner->m_pProperties->m_dwStates |= ~FWL_WGTSTATE_Deactivated;
1854  m_pOwner->Repaint(&m_pOwner->m_rtClient);
1855}
1856void CFWL_EditImpDelegate::DoDeactivate(CFWL_MsgDeactivate* pMsg) {
1857  m_pOwner->m_pProperties->m_dwStates &= FWL_WGTSTATE_Deactivated;
1858  m_pOwner->Repaint(&m_pOwner->m_rtClient);
1859}
1860void CFWL_EditImpDelegate::DoButtonDown(CFWL_MsgMouse* pMsg) {
1861  if ((m_pOwner->m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) == 0) {
1862    m_pOwner->SetFocus(TRUE);
1863  }
1864  if (!m_pOwner->m_pEdtEngine) {
1865    m_pOwner->UpdateEditEngine();
1866  }
1867  IFDE_TxtEdtPage* pPage = m_pOwner->m_pEdtEngine->GetPage(0);
1868  if (!pPage)
1869    return;
1870  CFX_PointF pt;
1871  pt.Set(pMsg->m_fx, pMsg->m_fy);
1872  m_pOwner->DeviceToEngine(pt);
1873  FX_BOOL bBefore = TRUE;
1874  int32_t nIndex = pPage->GetCharIndex(pt, bBefore);
1875  if (nIndex < 0) {
1876    nIndex = 0;
1877  }
1878  m_pOwner->m_pEdtEngine->SetCaretPos(nIndex, bBefore);
1879}
1880void CFWL_EditImpDelegate::OnFocusChanged(CFWL_Message* pMsg, FX_BOOL bSet) {
1881  FX_DWORD dwStyleEx = m_pOwner->GetStylesEx();
1882  FX_BOOL bRepaint = dwStyleEx & FWL_STYLEEXT_EDT_InnerCaret;
1883  if (bSet) {
1884    m_pOwner->m_pProperties->m_dwStates |= FWL_WGTSTATE_Focused;
1885    if (!m_pOwner->m_pEdtEngine) {
1886      m_pOwner->UpdateEditEngine();
1887    }
1888    m_pOwner->UpdateVAlignment();
1889    m_pOwner->UpdateOffset();
1890    m_pOwner->UpdateCaret();
1891  } else if (m_pOwner->m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) {
1892    m_pOwner->m_pProperties->m_dwStates &= ~FWL_WGTSTATE_Focused;
1893    m_pOwner->ShowCaret(FALSE);
1894    if (m_pOwner->m_pEdtEngine &&
1895        (dwStyleEx & FWL_STYLEEXT_EDT_NoHideSel) == 0) {
1896      int32_t nSel = m_pOwner->CountSelRanges();
1897      if (nSel > 0) {
1898        m_pOwner->ClearSelections();
1899        bRepaint = TRUE;
1900      }
1901      m_pOwner->SetCaretPos(0);
1902      m_pOwner->UpdateOffset();
1903    }
1904    m_pOwner->ClearRecord();
1905  }
1906  m_pOwner->LayoutScrollBar();
1907  if (bRepaint) {
1908    CFX_RectF rtInvalidate;
1909    rtInvalidate.Set(0, 0, m_pOwner->m_pProperties->m_rtWidget.width,
1910                     m_pOwner->m_pProperties->m_rtWidget.height);
1911    m_pOwner->Repaint(&rtInvalidate);
1912  }
1913}
1914void CFWL_EditImpDelegate::OnLButtonDown(CFWL_MsgMouse* pMsg) {
1915  DoCursor(pMsg);
1916  if (m_pOwner->m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled) {
1917    return;
1918  }
1919  m_pOwner->m_bLButtonDown = TRUE;
1920  m_pOwner->SetGrab(TRUE);
1921  DoButtonDown(pMsg);
1922  int32_t nIndex = m_pOwner->m_pEdtEngine->GetCaretPos();
1923  FX_BOOL bRepaint = FALSE;
1924  int32_t iCount = m_pOwner->m_pEdtEngine->CountSelRanges();
1925  if (iCount > 0) {
1926    m_pOwner->m_pEdtEngine->ClearSelection();
1927    bRepaint = TRUE;
1928  }
1929  FX_BOOL bShift = pMsg->m_dwFlags & FWL_KEYFLAG_Shift;
1930  if (bShift && m_pOwner->m_nSelStart != nIndex) {
1931    int32_t iStart = std::min(m_pOwner->m_nSelStart, nIndex);
1932    int32_t iEnd = std::max(m_pOwner->m_nSelStart, nIndex);
1933    m_pOwner->m_pEdtEngine->AddSelRange(iStart, iEnd - iStart);
1934    bRepaint = TRUE;
1935  } else {
1936    m_pOwner->m_nSelStart = nIndex;
1937  }
1938  if (bRepaint) {
1939    m_pOwner->Repaint(&m_pOwner->m_rtEngine);
1940  }
1941}
1942void CFWL_EditImpDelegate::OnLButtonUp(CFWL_MsgMouse* pMsg) {
1943  DoCursor(pMsg);
1944  m_pOwner->m_bLButtonDown = FALSE;
1945  m_pOwner->SetGrab(FALSE);
1946}
1947void CFWL_EditImpDelegate::OnButtonDblClk(CFWL_MsgMouse* pMsg) {
1948  if (!m_pOwner->m_pEdtEngine)
1949    return;
1950  DoCursor(pMsg);
1951  IFDE_TxtEdtPage* pPage = m_pOwner->m_pEdtEngine->GetPage(0);
1952  if (!pPage)
1953    return;
1954  CFX_PointF pt;
1955  pt.Set(pMsg->m_fx, pMsg->m_fy);
1956  m_pOwner->DeviceToEngine(pt);
1957  int32_t nCount = 0;
1958  int32_t nIndex = pPage->SelectWord(pt, nCount);
1959  if (nIndex < 0) {
1960    return;
1961  }
1962  m_pOwner->m_pEdtEngine->AddSelRange(nIndex, nCount);
1963  m_pOwner->m_pEdtEngine->SetCaretPos(nIndex + nCount - 1, FALSE);
1964  m_pOwner->Repaint(&m_pOwner->m_rtEngine);
1965}
1966void CFWL_EditImpDelegate::OnMouseMove(CFWL_MsgMouse* pMsg) {
1967  if (!m_pOwner->m_pEdtEngine)
1968    return;
1969  DoCursor(pMsg);
1970  if (m_pOwner->m_nSelStart == -1 || !m_pOwner->m_bLButtonDown) {
1971    return;
1972  }
1973  IFDE_TxtEdtPage* pPage = m_pOwner->m_pEdtEngine->GetPage(0);
1974  if (!pPage)
1975    return;
1976  CFX_PointF pt;
1977  pt.Set(pMsg->m_fx, pMsg->m_fy);
1978  m_pOwner->DeviceToEngine(pt);
1979  FX_BOOL bBefore = TRUE;
1980  int32_t nIndex = pPage->GetCharIndex(pt, bBefore);
1981  m_pOwner->m_pEdtEngine->SetCaretPos(nIndex, bBefore);
1982  nIndex = m_pOwner->m_pEdtEngine->GetCaretPos();
1983  m_pOwner->m_pEdtEngine->ClearSelection();
1984  if (nIndex != m_pOwner->m_nSelStart) {
1985    int32_t nLen = m_pOwner->m_pEdtEngine->GetTextLength();
1986    if (m_pOwner->m_nSelStart >= nLen) {
1987      m_pOwner->m_nSelStart = nLen;
1988    }
1989    m_pOwner->m_pEdtEngine->AddSelRange(
1990        std::min(m_pOwner->m_nSelStart, nIndex),
1991        FXSYS_abs(nIndex - m_pOwner->m_nSelStart));
1992  }
1993}
1994void CFWL_EditImpDelegate::OnKeyDown(CFWL_MsgKey* pMsg) {
1995  if (!m_pOwner->m_pEdtEngine)
1996    return;
1997  FDE_TXTEDTMOVECARET MoveCaret = MC_MoveNone;
1998  FX_BOOL bShift = pMsg->m_dwFlags & FWL_KEYFLAG_Shift;
1999  FX_BOOL bCtrl = pMsg->m_dwFlags & FWL_KEYFLAG_Ctrl;
2000  FX_DWORD dwKeyCode = pMsg->m_dwKeyCode;
2001  switch (dwKeyCode) {
2002    case FWL_VKEY_Left: {
2003      MoveCaret = MC_Left;
2004      break;
2005    }
2006    case FWL_VKEY_Right: {
2007      MoveCaret = MC_Right;
2008      break;
2009    }
2010    case FWL_VKEY_Up: {
2011      MoveCaret = MC_Up;
2012      break;
2013    }
2014    case FWL_VKEY_Down: {
2015      MoveCaret = MC_Down;
2016      break;
2017    }
2018    case FWL_VKEY_Home: {
2019      if (bCtrl) {
2020        MoveCaret = MC_Home;
2021      } else {
2022        MoveCaret = MC_LineStart;
2023      }
2024      break;
2025    }
2026    case FWL_VKEY_End: {
2027      if (bCtrl) {
2028        MoveCaret = MC_End;
2029      } else {
2030        MoveCaret = MC_LineEnd;
2031      }
2032      break;
2033    }
2034    case FWL_VKEY_Insert: {
2035      break;
2036    }
2037    case FWL_VKEY_Delete: {
2038      if ((m_pOwner->m_pProperties->m_dwStyleExes &
2039           FWL_STYLEEXT_EDT_ReadOnly) ||
2040          (m_pOwner->m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled)) {
2041        break;
2042      }
2043      int32_t nCaret = m_pOwner->m_pEdtEngine->GetCaretPos();
2044#if (_FX_OS_ == _FX_MACOSX_)
2045      m_pOwner->m_pEdtEngine->Delete(nCaret, TRUE);
2046#else
2047      m_pOwner->m_pEdtEngine->Delete(nCaret);
2048#endif
2049      break;
2050    }
2051    case FWL_VKEY_F2: {
2052      break;
2053    }
2054    case FWL_VKEY_Tab: {
2055      m_pOwner->DispatchKeyEvent(pMsg);
2056      break;
2057    }
2058    default: {
2059#if (_FX_OS_ == _FX_MACOSX_)
2060      if (pMsg->m_dwFlags & FWL_KEYFLAG_Command)
2061#else
2062      if (pMsg->m_dwFlags & FWL_KEYFLAG_Ctrl)
2063#endif
2064      {
2065        if (dwKeyCode == 0x43 || dwKeyCode == 0x63) {
2066          m_pOwner->DoClipboard(1);
2067          return;
2068        }
2069        if (dwKeyCode == 0x58 || dwKeyCode == 0x78) {
2070          m_pOwner->DoClipboard(2);
2071          return;
2072        }
2073        if (dwKeyCode == 0x56 || dwKeyCode == 0x76) {
2074          m_pOwner->DoClipboard(3);
2075          return;
2076        }
2077      }
2078    }
2079  }
2080  if (MoveCaret != MC_MoveNone) {
2081    m_pOwner->m_pEdtEngine->MoveCaretPos(MoveCaret, bShift, bCtrl);
2082  }
2083}
2084void CFWL_EditImpDelegate::OnChar(CFWL_MsgKey* pMsg) {
2085  if ((m_pOwner->m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_ReadOnly) ||
2086      (m_pOwner->m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled)) {
2087    return;
2088  }
2089  if (!m_pOwner->m_pEdtEngine)
2090    return;
2091  int32_t iError = 0;
2092  FX_WCHAR c = (FX_WCHAR)pMsg->m_dwKeyCode;
2093  int32_t nCaret = m_pOwner->m_pEdtEngine->GetCaretPos();
2094  switch (c) {
2095    case FWL_VKEY_Back: {
2096      m_pOwner->m_pEdtEngine->Delete(nCaret, TRUE);
2097      break;
2098    }
2099    case 0x0A: {
2100      break;
2101    }
2102    case FWL_VKEY_Escape: {
2103      break;
2104    }
2105    case FWL_VKEY_Tab: {
2106      iError = m_pOwner->m_pEdtEngine->Insert(nCaret, L"\t", 1);
2107      break;
2108    }
2109    case FWL_VKEY_Return: {
2110      if (m_pOwner->m_pProperties->m_dwStyleExes &
2111          FWL_STYLEEXT_EDT_WantReturn) {
2112        iError = m_pOwner->m_pEdtEngine->Insert(nCaret, L"\n", 1);
2113      }
2114      break;
2115    }
2116    default: {
2117      if (!m_pOwner->m_pWidgetMgr->IsFormDisabled()) {
2118        if (m_pOwner->m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_Number) {
2119          if (((pMsg->m_dwKeyCode < FWL_VKEY_0) &&
2120               (pMsg->m_dwKeyCode != 0x2E && pMsg->m_dwKeyCode != 0x2D)) ||
2121              pMsg->m_dwKeyCode > FWL_VKEY_9) {
2122            break;
2123          }
2124          if (!m_pOwner->ValidateNumberChar(c)) {
2125            break;
2126          }
2127        }
2128      }
2129#if (_FX_OS_ == _FX_MACOSX_)
2130      if (pMsg->m_dwFlags & FWL_KEYFLAG_Command)
2131#else
2132      if (pMsg->m_dwFlags & FWL_KEYFLAG_Ctrl)
2133#endif
2134      {
2135        break;
2136      }
2137      iError = m_pOwner->m_pEdtEngine->Insert(nCaret, &c, 1);
2138      break;
2139    }
2140  }
2141  if (iError < 0) {
2142    m_pOwner->ProcessInsertError(iError);
2143  }
2144}
2145FX_BOOL CFWL_EditImpDelegate::OnScroll(IFWL_ScrollBar* pScrollBar,
2146                                       FX_DWORD dwCode,
2147                                       FX_FLOAT fPos) {
2148  CFX_SizeF fs;
2149  pScrollBar->GetRange(fs.x, fs.y);
2150  FX_FLOAT iCurPos = pScrollBar->GetPos();
2151  FX_FLOAT fStep = pScrollBar->GetStepSize();
2152  switch (dwCode) {
2153    case FWL_SCBCODE_Min: {
2154      fPos = fs.x;
2155      break;
2156    }
2157    case FWL_SCBCODE_Max: {
2158      fPos = fs.y;
2159      break;
2160    }
2161    case FWL_SCBCODE_StepBackward: {
2162      fPos -= fStep;
2163      if (fPos < fs.x + fStep / 2) {
2164        fPos = fs.x;
2165      }
2166      break;
2167    }
2168    case FWL_SCBCODE_StepForward: {
2169      fPos += fStep;
2170      if (fPos > fs.y - fStep / 2) {
2171        fPos = fs.y;
2172      }
2173      break;
2174    }
2175    case FWL_SCBCODE_PageBackward: {
2176      fPos -= pScrollBar->GetPageSize();
2177      if (fPos < fs.x) {
2178        fPos = fs.x;
2179      }
2180      break;
2181    }
2182    case FWL_SCBCODE_PageForward: {
2183      fPos += pScrollBar->GetPageSize();
2184      if (fPos > fs.y) {
2185        fPos = fs.y;
2186      }
2187      break;
2188    }
2189    case FWL_SCBCODE_Pos:
2190    case FWL_SCBCODE_TrackPos: {
2191      break;
2192    }
2193    case FWL_SCBCODE_EndScroll: {
2194      return FALSE;
2195    }
2196    default: {}
2197  }
2198  if (iCurPos != fPos) {
2199    pScrollBar->SetPos(fPos);
2200    pScrollBar->SetTrackPos(fPos);
2201    m_pOwner->UpdateOffset(pScrollBar, fPos - iCurPos);
2202    if (m_pOwner->m_pEdtEngine) {
2203      m_pOwner->UpdateCaret();
2204    }
2205    CFX_RectF rect;
2206    m_pOwner->GetWidgetRect(rect);
2207    CFX_RectF rtInvalidate;
2208    rtInvalidate.Set(0, 0, rect.width + 2, rect.height + 2);
2209    m_pOwner->Repaint(&rtInvalidate);
2210  }
2211  return TRUE;
2212}
2213void CFWL_EditImpDelegate::DoCursor(CFWL_MsgMouse* pMsg) {
2214  if (m_pOwner->m_rtClient.Contains(pMsg->m_fx, pMsg->m_fy)) {
2215    IFWL_AdapterNative* pNative = FWL_GetAdapterNative();
2216    IFWL_AdapterCursorMgr* pCursorMgr = pNative->GetCursorMgr();
2217    if (NULL != pCursorMgr) {
2218      FWL_HCURSOR hCursor =
2219          pCursorMgr->GetSystemCursor(FWL_CURSORTYPE_InputBeam);
2220      pCursorMgr->SetCursor(hCursor);
2221      pCursorMgr->ShowCursor(TRUE);
2222    }
2223  }
2224}
2225