4#include "Stroika/Frameworks/StroikaPreComp.h"
13#include "Stroika/Frameworks/Led/Command.h"
14#include "Stroika/Frameworks/Led/Config.h"
15#include "Stroika/Frameworks/Led/IdleManager.h"
16#include "Stroika/Frameworks/Led/Marker.h"
17#include "Stroika/Frameworks/Led/TextInteractor.h"
18#include "Stroika/Frameworks/Led/TextStore.h"
23using namespace Stroika::Frameworks;
24using namespace Stroika::Frameworks::Led;
26#if qStroika_Frameworks_Led_SupportGDI
27using SavedTextRep = InteractiveReplaceCommand::SavedTextRep;
30 class FlavorSavorTextRep :
public SavedTextRep {
32 using inherited = SavedTextRep;
35 FlavorSavorTextRep (TextInteractor* interactor,
size_t regionStart,
size_t regionEnd,
size_t selStart,
size_t selEnd)
36 : inherited (selStart, selEnd)
38 , fTextLength (regionEnd - regionStart)
40#if !qFailToLookupFunctionNameWhenCompilingFunctionLocalClassMethodCompilerBug
43 interactor->GetExternalizer ()->ExternalizeBestFlavor (fSavedText, regionStart, regionEnd);
45 virtual size_t GetLength ()
const override
49 virtual void InsertSelf (TextInteractor* interactor,
size_t at,
size_t nBytesToOverwrite)
override
51#if !qFailToLookupFunctionNameWhenCompilingFunctionLocalClassMethodCompilerBug
54 interactor->GetInternalizer ()->InternalizeBestFlavor (fSavedText, at, at + nBytesToOverwrite);
65 inline bool IsSmartSpace (Led_tChar c)
67 return (c ==
' ' or c ==
'\t');
69 inline bool IsShouldBeSepWithWhitespaceWordChar (Led_tChar c)
77 return Character (c).IsAlphaNumeric () and c < 127;
82 class MyCallback :
public TextInteractor::DialogSupport::SpellCheckDialogCallback {
84 using inherited = TextInteractor::DialogSupport::SpellCheckDialogCallback;
87 MyCallback (TextInteractor& ti)
94 DISABLE_COMPILER_MSC_WARNING_START (6262)
95 virtual MisspellingInfo* GetNextMisspelling ()
override
97 SpellCheckEngine* sce = fTI.GetSpellCheckEngine ();
99 Led_tChar charBuf[10 * 1024];
100 bool firstTry =
true;
101 size_t startRegion = fTI.GetSelectionEnd ();
106 size_t wordStart = 0;
108 bool wordReal =
false;
109 fTI.GetTextStore ().FindWordBreaks (startRegion, &wordStart, &wordEnd, &wordReal, sce->PeekAtTextBreaksUsed ());
110 if (wordReal and wordStart + Memory::NEltsOf (charBuf) > startRegion) {
111 startRegion = wordStart;
114 size_t endRegion = min (startRegion + Memory::NEltsOf (charBuf), fTI.GetEnd ());
115 fTI.CopyOut (startRegion, endRegion - startRegion, charBuf);
116 const Led_tChar* cursor =
nullptr;
117 const Led_tChar* wordStart =
nullptr;
118 const Led_tChar* wordEnd =
nullptr;
119 if (sce->ScanForUndefinedWord (charBuf, charBuf + (endRegion - startRegion), &cursor, &wordStart, &wordEnd)) {
124 if (wordStart != charBuf and wordEnd == charBuf + (endRegion - startRegion)) {
125 startRegion += (wordStart - charBuf);
129 Led_tString undefinedWord = Led_tString{wordStart, wordEnd};
130 if (fIgnoredWords.find (undefinedWord) != fIgnoredWords.end ()) {
133 startRegion += (wordEnd - charBuf);
136 MisspellingInfo* mi =
new MisspellingInfo ();
137 mi->fUndefinedWord = undefinedWord;
138 mi->fSuggestions = sce->GenerateSuggestions (mi->fUndefinedWord);
139 size_t selStart = startRegion + wordStart - charBuf;
140 size_t selEnd = selStart + (wordEnd - wordStart);
141 fTI.SetSelection (selStart, selEnd);
142 fTI.ScrollToSelection ();
145 else if (endRegion < fTI.GetEnd ()) {
148 startRegion = endRegion;
160 DISABLE_COMPILER_MSC_WARNING_END (6262)
161 virtual
void DoIgnore ()
override
163 fTI.SetSelection (fTI.GetSelectionEnd (), fTI.GetSelectionEnd ());
164 fTI.ScrollToSelection ();
166 virtual void DoIgnoreAll ()
override
169 size_t origSelStart = fTI.GetSelectionStart ();
170 size_t origSelEnd = fTI.GetSelectionEnd ();
172 fTI.CopyOut (origSelStart, origSelEnd - origSelStart, text.data ());
173 Led_tString ignoredWord = Led_tString{text.
data (), origSelEnd - origSelStart};
174 fIgnoredWords.insert (ignoredWord);
178 virtual void DoChange (
const Led_tString& changeTo)
override
180 size_t origSelStart = fTI.GetSelectionStart ();
181 size_t origSelEnd = fTI.GetSelectionEnd ();
182 TextInteractor::SearchParameters sp;
185 fTI.CopyOut (origSelStart, origSelEnd - origSelStart, text.data ());
186 sp.fMatchString = Led_tString{text.
data (), origSelEnd - origSelStart};
188 fTI.SetSelection (origSelStart, origSelStart);
189 fTI.OnDoReplaceCommand (sp, changeTo);
191 virtual void DoChangeAll (
const Led_tString& changeTo)
override
193 size_t origSelStart = fTI.GetSelectionStart ();
194 size_t origSelEnd = fTI.GetSelectionEnd ();
195 TextInteractor::SearchParameters sp;
198 fTI.CopyOut (origSelStart, origSelEnd - origSelStart, text.data ());
199 sp.fMatchString = Led_tString{text.
data (), origSelEnd - origSelStart};
201 fTI.OnDoReplaceAllCommand (sp, changeTo);
203 virtual bool AddToDictionaryEnabled ()
const override
205 SpellCheckEngine* sce = fTI.GetSpellCheckEngine ();
206 if (sce !=
nullptr) {
207 SpellCheckEngine::UDInterface* udi = sce->GetUDInterface ();
208 if (udi !=
nullptr) {
209 return udi->AddWordToUserDictionarySupported ();
214 virtual void AddToDictionary (
const Led_tString& newWord)
override
216 SpellCheckEngine* sce = fTI.GetSpellCheckEngine ();
217 if (sce !=
nullptr) {
218 SpellCheckEngine::UDInterface* udi = sce->GetUDInterface ();
219 if (udi !=
nullptr) {
220 udi->AddWordToUserDictionary (newWord);
224 fTI.SetSelection (fTI.GetSelectionEnd (), fTI.GetSelectionEnd ());
225 fTI.ScrollToSelection ();
227 virtual void LookupOnWeb (
const Led_tString& word)
override
229 const char kURLBase[] =
"http://dictionary.reference.com/search?q=";
230 Led_URLManager::Get ().Open (kURLBase + Led_tString2ANSIString (word));
232 virtual bool OptionsDialogEnabled ()
const override
237 virtual void OptionsDialog ()
override
244 set<Led_tString> fIgnoredWords;
254void TextInteractor::DialogSupport::DisplayFindDialog (Led_tString* ,
const vector<Led_tString>& ,
255 bool* ,
bool* ,
bool* ,
bool* )
279TextInteractor::DialogSupport::ReplaceButtonPressed
280TextInteractor::DialogSupport::DisplayReplaceDialog (Led_tString* ,
const vector<Led_tString>& ,
281 Led_tString* ,
bool* ,
bool* ,
bool* )
284 return eReplaceButton_Cancel;
287void TextInteractor::DialogSupport::DisplaySpellCheckDialog (SpellCheckDialogCallback& )
297TextInteractor::UndoableContextHelper::UndoableContextHelper (TextInteractor& ti,
const SDKString& cmdName,
bool allowSmartCNPExpansion)
298 : fSimplePlainTextInsertOptimization (false)
299 , fTextInteractor (ti)
301 , fSelStart (ti.GetSelectionStart ())
302 , fSelEnd (ti.GetSelectionEnd ())
304 , fCommandComplete (false)
306 if (allowSmartCNPExpansion) {
307 ti.OptionallyExpandSelectionForSmartCutAndPasteModeDeletes (&fSelStart, &fSelEnd);
309 if (ti.GetCommandHandler () !=
nullptr) {
310 ti.PreInteractiveUndoHelper (&fBefore, fSelStart, fSelEnd, ti.GetSelectionStart (), ti.GetSelectionEnd ());
314TextInteractor::UndoableContextHelper::UndoableContextHelper (TextInteractor& ti,
const SDKString& cmdName,
size_t regionAndSelStart,
315 size_t regionAndSelEnd,
bool allowSmartCNPExpansion)
316 : fSimplePlainTextInsertOptimization (false)
317 , fTextInteractor (ti)
319 , fSelStart (regionAndSelStart)
320 , fSelEnd (regionAndSelEnd)
322 , fCommandComplete (false)
324 if (allowSmartCNPExpansion) {
325 ti.OptionallyExpandSelectionForSmartCutAndPasteModeDeletes (&fSelStart, &fSelEnd);
327 if (ti.GetCommandHandler () !=
nullptr) {
328 ti.PreInteractiveUndoHelper (&fBefore, fSelStart, fSelEnd, regionAndSelStart, regionAndSelEnd);
332TextInteractor::UndoableContextHelper::UndoableContextHelper (TextInteractor& ti,
const SDKString& cmdName,
size_t regionStart,
333 size_t regionEnd,
size_t selStart,
size_t selEnd,
bool allowSmartCNPExpansion)
334 : fSimplePlainTextInsertOptimization (false)
335 , fTextInteractor (ti)
337 , fSelStart (regionStart)
338 , fSelEnd (regionEnd)
340 , fCommandComplete (false)
342 if (allowSmartCNPExpansion) {
343 ti.OptionallyExpandSelectionForSmartCutAndPasteModeDeletes (&fSelStart, &fSelEnd);
345 if (ti.GetCommandHandler () !=
nullptr) {
346 ti.PreInteractiveUndoHelper (&fBefore, fSelStart, fSelEnd, selStart, selEnd);
350TextInteractor::UndoableContextHelper::~UndoableContextHelper ()
352 if (not fCommandComplete) {
371void TextInteractor::UndoableContextHelper::CommandComplete ()
373 fTextInteractor.ScrollToSelection ();
374 if (fTextInteractor.GetCommandHandler () !=
nullptr) {
375 if (GetSimplePlainTextInsertOptimization ()) {
376 fTextInteractor.PostInteractiveSimpleCharInsertUndoHelper (&fBefore, fSelStart, fTextInteractor.GetSelectionEnd (), fCmdName);
379 fTextInteractor.PostInteractiveUndoHelper (&fBefore, fSelStart, fTextInteractor.GetSelectionEnd (), fCmdName);
382 fCommandComplete =
true;
385void TextInteractor::UndoableContextHelper::CommandComplete (
size_t endOfInsert)
387 fTextInteractor.ScrollToSelection ();
388 if (fTextInteractor.GetCommandHandler () !=
nullptr) {
389 if (GetSimplePlainTextInsertOptimization ()) {
390 fTextInteractor.PostInteractiveSimpleCharInsertUndoHelper (&fBefore, fSelStart, endOfInsert, fCmdName);
393 fTextInteractor.PostInteractiveUndoHelper (&fBefore, fSelStart, endOfInsert, fCmdName);
396 fCommandComplete =
true;
404TextInteractor::PreReplaceInfo::PreReplaceInfo ()
405 : fTextInteractor (nullptr)
406 , fUpdateMode (TextInteractor::eNoUpdate)
409 , fWithWhatCharCount (0)
410 , fBoundingUpdateMarker ()
411 , fBoundingUpdateHeight (0)
412 , fStableTypingRegionHeight (0)
416TextInteractor::PreReplaceInfo::~PreReplaceInfo ()
418 if (fTextInteractor !=
nullptr) {
419 fTextInteractor->GetTextStore ().RemoveMarker (&fBoundingUpdateMarker);
420 fTextInteractor =
nullptr;
424TextInteractor::UpdateMode TextInteractor::PreReplaceInfo::GetUpdateMode ()
const
429size_t TextInteractor::PreReplaceInfo::GetFrom ()
const
434size_t TextInteractor::PreReplaceInfo::GetTo ()
const
445TextInteractor::CommandNames TextInteractor::sCommandNames = TextInteractor::MakeDefaultCommandNames ();
446TextInteractor::DialogSupport* TextInteractor::sDialogSupport =
nullptr;
447TextInteractor::SearchParameters TextInteractor::sSearchParameters;
448TextInteractor::ReplaceParameters TextInteractor::sReplaceParameters;
450TextInteractor::TextInteractor ()
451 : fCommandHandler (nullptr)
452 , fSpellCheckEngine (nullptr)
453 , fSuppressCommandBreaksContext (false)
454 , fDefaultUpdateMode (eDelayedUpdate)
455 , fSmartCutAndPasteMode (true)
457 , fLastMouseDownAt (Led_Point (0, 0))
458 , fWholeWindowInvalid (false)
459 , fUseSecondaryHilight (false)
460 , fUseBitmapScrollingOptimization (true)
461 , fSuppressTypedControlCharacters (true)
462 , fInteractiveUpdadeMode (eIndeterminateInteractiveUpdateMode)
463 , fTmpPreReplaceInfo ()
464 , fDoingUpdateModeReplaceOn (nullptr)
465 , fCaretShown (false)
466 , fLeftSideOfSelectionInteresting (false)
467 , fCaretShownAfterPos (true)
472 fScrollBarParamsValid (false)
474 fScrollBarType[h] = eScrollBarNever;
475 fScrollBarType[v] = eScrollBarNever;
478TextInteractor::~TextInteractor ()
480 Assert (fCommandHandler ==
nullptr);
482 Assert (fSpellCheckEngine ==
nullptr);
485TextInteractor::CommandNames TextInteractor::MakeDefaultCommandNames ()
487 TextInteractor::CommandNames cmdNames;
488 cmdNames.fTypingCommandName = Led_SDK_TCHAROF (
"Typing");
489 cmdNames.fCutCommandName = Led_SDK_TCHAROF (
"Cut");
490 cmdNames.fClearCommandName = Led_SDK_TCHAROF (
"Clear");
491 cmdNames.fPasteCommandName = Led_SDK_TCHAROF (
"Paste");
492 cmdNames.fUndoFormatString = Led_SDK_TCHAROF (
"Undo %s");
493 cmdNames.fRedoFormatString = Led_SDK_TCHAROF (
"ReDo %s");
494#if qStroika_Foundation_Common_Platform_Windows
495 cmdNames.fUndoFormatString += Led_SDK_TCHAROF (
"\tCtrl+Z");
496 cmdNames.fRedoFormatString += Led_SDK_TCHAROF (
"\tCtrl+Y");
498 cmdNames.fReplaceCommandName = Led_SDK_TCHAROF (
"Replace");
499 cmdNames.fReplaceAllCommandName = Led_SDK_TCHAROF (
"Replace All");
500 cmdNames.fReplaceAllInSelectionCommandName = Led_SDK_TCHAROF (
"Replace All In Selection");
510bool TextInteractor::OnUpdateCommand (CommandUpdater* enabler)
513 switch (enabler->GetCmdID ()) {
514 case kSelectAll_CmdID: {
515 enabler->SetEnabled (
true);
519 OnUpdateCutCopyClearCommand (enabler);
523 OnUpdateCutCopyClearCommand (enabler);
527 OnUpdatePasteCommand (enabler);
531 OnUpdateCutCopyClearCommand (enabler);
535 OnUpdateUndoRedoCommand (enabler);
539 OnUpdateUndoRedoCommand (enabler);
543 OnUpdateFindCommands (enabler);
546 case kFindAgain_CmdID: {
547 OnUpdateFindCommands (enabler);
550 case kEnterFindString_CmdID: {
551 OnUpdateFindCommands (enabler);
554 case kReplace_CmdID: {
555 OnUpdateFindCommands (enabler);
558 case kReplaceAgain_CmdID: {
559 OnUpdateFindCommands (enabler);
562 case kSpellCheck_CmdID: {
563 OnUpdateSpellCheckCommand (enabler);
566 case kSelectWord_CmdID:
567 case kSelectTextRow_CmdID:
568 case kSelectParagraph_CmdID: {
569 OnUpdateSelectTextCommand (enabler);
582bool TextInteractor::OnPerformCommand (CommandNumber commandNumber)
584 switch (commandNumber) {
585 case kSelectAll_CmdID: {
586 OnSelectAllCommand ();
617 case kFindAgain_CmdID: {
618 OnFindAgainCommand ();
621 case kEnterFindString_CmdID: {
622 OnEnterFindString ();
625 case kReplace_CmdID: {
629 case kReplaceAgain_CmdID: {
630 OnReplaceAgainCommand ();
633 case kSpellCheck_CmdID: {
634 OnSpellCheckCommand ();
637 case kSelectWord_CmdID:
638 case kSelectTextRow_CmdID:
639 case kSelectParagraph_CmdID: {
640 OnPerformSelectTextCommand (commandNumber);
647void TextInteractor::OnUpdateCutCopyClearCommand (CommandUpdater* enabler)
652 static_cast<TextImager*
> (
this)->GetSelection (&start, &end);
653 enabler->SetEnabled (start != end);
656void TextInteractor::OnUpdatePasteCommand (CommandUpdater* enabler)
660 enabler->SetEnabled (
true);
663void TextInteractor::OnUpdateUndoRedoCommand (CommandUpdater* enabler)
666 if (GetCommandHandler () ==
nullptr) {
667 enabler->SetEnabled (
false);
670 if (enabler->GetCmdID () == kUndo_CmdID) {
671 enabler->SetEnabled (GetCommandHandler ()->CanUndo ());
674 Characters::CString::Format (GetCommandNames ().fUndoFormatString.c_str (), GetCommandHandler ()->GetUndoCmdName ());
675 enabler->SetText (menuItemText.c_str ());
677 else if (enabler->GetCmdID () == kRedo_CmdID) {
678 enabler->SetEnabled (GetCommandHandler ()->CanRedo ());
681 Characters::CString::Format (GetCommandNames ().fRedoFormatString.c_str (), GetCommandHandler ()->GetRedoCmdName ());
682 enabler->SetText (menuItemText.c_str ());
687void TextInteractor::OnUpdateSelectTextCommand (CommandUpdater* enabler)
690 enabler->SetEnabled (
true);
693void TextInteractor::OnPerformSelectTextCommand (CommandNumber commandNumber)
696 size_t oldSelStart = GetSelectionStart ();
697 size_t oldSelEnd = GetSelectionEnd ();
698 size_t newSelStart = oldSelStart;
699 size_t newSelEnd = oldSelEnd;
700 switch (commandNumber) {
701 case kSelectWord_CmdID: {
702 size_t wordStart = 0;
704 bool wordReal =
false;
705 GetTextStore ().FindWordBreaks (oldSelStart, &wordStart, &wordEnd, &wordReal);
707 Assert (wordStart <= oldSelStart);
708 newSelStart = wordStart;
712 GetTextStore ().FindWordBreaks (FindPreviousCharacter (oldSelStart), &wordStart, &wordEnd, &wordReal);
714 Assert (wordStart <= oldSelStart);
715 newSelStart = wordStart;
719 GetTextStore ().FindWordBreaks (oldSelEnd, &wordStart, &wordEnd, &wordReal);
724 case kSelectTextRow_CmdID: {
725 newSelStart = GetStartOfRowContainingPosition (oldSelStart);
728 if (oldSelStart == oldSelEnd or oldSelEnd != GetStartOfRowContainingPosition (oldSelEnd)) {
729 newSelEnd = GetEndOfRowContainingPosition (oldSelEnd);
732 case kSelectParagraph_CmdID: {
733 newSelStart = GetTextStore ().GetStartOfLineContainingPosition (oldSelStart);
737 if (oldSelStart == oldSelEnd or oldSelEnd != GetTextStore ().GetStartOfLineContainingPosition (oldSelEnd)) {
738 newSelEnd = GetTextStore ().GetEndOfLineContainingPosition (oldSelEnd);
740 if (newSelEnd < GetEnd ()) {
742 GetTextStore ().CopyOut (newSelEnd, 1, &c);
744 newSelEnd = FindNextCharacter (newSelEnd);
750 SetSelection (newSelStart, newSelEnd);
754 vector<Led_tString> MergeRecentFindStrings (
const Led_tString& s,
const vector<Led_tString>& oldRecents);
757void TextInteractor::OnFindCommand ()
759 SearchParameters parameters = GetSearchParameters ();
760 bool pressedOK =
false;
761 GetDialogSupport ().DisplayFindDialog (¶meters.fMatchString, parameters.fRecentFindStrings, ¶meters.fWrapSearch,
762 ¶meters.fWholeWordSearch, ¶meters.fCaseSensativeSearch, &pressedOK);
763 parameters.fRecentFindStrings = MergeRecentFindStrings (parameters.fMatchString, parameters.fRecentFindStrings);
764 SetSearchParameters (parameters);
766 OnFindAgainCommand ();
770void TextInteractor::OnReplaceCommand ()
772 SearchParameters parameters = GetSearchParameters ();
773 ReplaceParameters rParameters = GetReplaceParameters ();
774 DialogSupport::ReplaceButtonPressed pressed =
775 GetDialogSupport ().DisplayReplaceDialog (¶meters.fMatchString, parameters.fRecentFindStrings, &rParameters.fReplaceWith,
776 ¶meters.fWrapSearch, ¶meters.fWholeWordSearch, ¶meters.fCaseSensativeSearch);
777 parameters.fRecentFindStrings = MergeRecentFindStrings (parameters.fMatchString, parameters.fRecentFindStrings);
778 SetSearchParameters (parameters);
779 SetReplaceParameters (rParameters);
781 case TextInteractor::DialogSupport::eReplaceButton_Find:
782 OnFindAgainCommand ();
784 case TextInteractor::DialogSupport::eReplaceButton_Replace:
785 OnDoReplaceCommand (parameters, rParameters.fReplaceWith);
787 case TextInteractor::DialogSupport::eReplaceButton_ReplaceAll:
788 OnDoReplaceAllCommand (parameters, rParameters.fReplaceWith);
790 case TextInteractor::DialogSupport::eReplaceButton_ReplaceAllInSelection:
791 OnDoReplaceAllInSelectionCommand (parameters, rParameters.fReplaceWith);
796void TextInteractor::OnReplaceAgainCommand ()
798 SearchParameters parameters = GetSearchParameters ();
799 ReplaceParameters rParameters = GetReplaceParameters ();
800 OnDoReplaceCommand (parameters, rParameters.fReplaceWith);
803void TextInteractor::OnDoReplaceCommand (
const SearchParameters& searchFor,
const Led_tString& replaceWith)
805 BreakInGroupedCommands ();
807 size_t origSelStart = GetSelectionStart ();
808 size_t origSelEnd = GetSelectionEnd ();
809 size_t whereTo = GetTextStore ().Find (searchFor, origSelEnd);
810 if ((whereTo == kBadIndex) or (whereTo == origSelStart and whereTo + searchFor.fMatchString.length () == origSelEnd)) {
814 InteractiveModeUpdater iuMode (*
this);
815 size_t replaceStart = whereTo;
816 size_t replaceEnd = whereTo + searchFor.fMatchString.length ();
817 UndoableContextHelper undoContext (*
this, GetCommandNames ().fReplaceCommandName, replaceStart, replaceEnd, GetSelectionStart (),
818 GetSelectionEnd (),
false);
820 InteractiveReplace_ (undoContext.GetUndoRegionStart (), undoContext.GetUndoRegionEnd (), replaceWith.c_str (), replaceWith.length ());
821 SetSelection (whereTo, whereTo + replaceWith.length ());
823 undoContext.CommandComplete ();
824 ScrollToSelection ();
826 BreakInGroupedCommands ();
829void TextInteractor::OnDoReplaceAllCommand (
const SearchParameters& searchFor,
const Led_tString& replaceWith)
831 InteractiveModeUpdater iuMode (*
this);
832 BreakInGroupedCommands ();
835 size_t whereTo = GetTextStore ().Find (searchFor, startAt, GetTextStore ().GetEnd ());
836 if (whereTo == kBadIndex) {
840 size_t replaceStart = whereTo;
841 size_t replaceEnd = whereTo + searchFor.fMatchString.length ();
842 UndoableContextHelper undoContext (*
this, GetCommandNames ().fReplaceAllCommandName, replaceStart, replaceEnd,
843 GetSelectionStart (), GetSelectionEnd (),
false);
845 InteractiveReplace_ (undoContext.GetUndoRegionStart (), undoContext.GetUndoRegionEnd (), replaceWith.c_str (), replaceWith.length ());
846 SetSelection (whereTo, whereTo + replaceWith.length ());
847 startAt = whereTo + replaceWith.length ();
849 undoContext.CommandComplete ();
852 ScrollToSelection ();
853 BreakInGroupedCommands ();
856void TextInteractor::OnDoReplaceAllInSelectionCommand (
const SearchParameters& searchFor,
const Led_tString& replaceWith)
858 InteractiveModeUpdater iuMode (*
this);
859 BreakInGroupedCommands ();
860 size_t startAt = GetSelectionStart ();
861 TempMarker selectionRegion (GetTextStore (), startAt, GetSelectionEnd ());
863 Assert (startAt <= selectionRegion.GetEnd ());
864 size_t whereTo = GetTextStore ().Find (searchFor, startAt, selectionRegion.GetEnd ());
865 if (whereTo == kBadIndex) {
869 size_t replaceStart = whereTo;
870 size_t replaceEnd = whereTo + searchFor.fMatchString.length ();
871 UndoableContextHelper undoContext (*
this, GetCommandNames ().fReplaceAllInSelectionCommandName, replaceStart, replaceEnd,
872 GetSelectionStart (), GetSelectionEnd (),
false);
874 InteractiveReplace_ (undoContext.GetUndoRegionStart (), undoContext.GetUndoRegionEnd (), replaceWith.c_str (), replaceWith.length ());
875 SetSelection (whereTo, whereTo + replaceWith.length ());
876 startAt = whereTo + replaceWith.length ();
878 undoContext.CommandComplete ();
881 ScrollToSelection ();
882 BreakInGroupedCommands ();
885void TextInteractor::OnFindAgainCommand ()
887 TextStore::SearchParameters parameters = GetSearchParameters ();
890 size_t origSelStart = GetSelectionStart ();
891 size_t origSelEnd = GetSelectionEnd ();
892 size_t whereTo = GetTextStore ().Find (parameters, origSelEnd);
893 if ((whereTo == kBadIndex) or (whereTo == origSelStart and whereTo + parameters.fMatchString.length () == origSelEnd)) {
897 SetSelection (whereTo, whereTo + parameters.fMatchString.length ());
898 ScrollToSelection ();
902void TextInteractor::OnEnterFindString ()
904 SearchParameters parameters = GetSearchParameters ();
906 size_t selStart = GetSelectionStart ();
907 size_t selEnd = GetSelectionEnd ();
908 size_t selLength = selEnd - selStart;
911 CopyOut (selStart, selLength, buf.data ());
912 parameters.fMatchString = Led_tString{buf.data (), selLength};
913 parameters.fRecentFindStrings = MergeRecentFindStrings (parameters.fMatchString, parameters.fRecentFindStrings);
914 SetSearchParameters (parameters);
917void TextInteractor::OnUpdateFindCommands (CommandUpdater* enabler)
920 if (enabler->GetCmdID () == kFind_CmdID) {
921 enabler->SetEnabled (
true);
923 else if (enabler->GetCmdID () == kFindAgain_CmdID) {
924 enabler->SetEnabled (GetSearchParameters ().fMatchString.length () != 0);
926 else if (enabler->GetCmdID () == kEnterFindString_CmdID) {
927 enabler->SetEnabled (GetSelectionStart () != GetSelectionEnd ());
929 else if (enabler->GetCmdID () == kReplace_CmdID) {
930 enabler->SetEnabled (
true);
932 else if (enabler->GetCmdID () == kReplaceAgain_CmdID) {
933 enabler->SetEnabled (GetSearchParameters ().fMatchString.length () != 0);
937TextInteractor::SearchParameters TextInteractor::GetSearchParameters ()
const
939 return sSearchParameters;
942void TextInteractor::SetSearchParameters (
const SearchParameters& sp)
944 sSearchParameters = sp;
947TextInteractor::ReplaceParameters TextInteractor::GetReplaceParameters ()
const
949 return sReplaceParameters;
952void TextInteractor::SetReplaceParameters (
const ReplaceParameters& rp)
954 sReplaceParameters = rp;
957vector<Led_tString> TextInteractor::MergeRecentFindStrings (
const Led_tString& s,
const vector<Led_tString>& oldRecents)
959 const unsigned int kMaxEntries = 20;
960 vector<Led_tString> result = oldRecents;
963 vector<Led_tString>::iterator i = std::find (result.begin (), result.end (), s);
964 if (i != result.end ()) {
967 result.insert (result.begin (), s);
968 if (result.size () > kMaxEntries) {
969 result.erase (result.begin () + kMaxEntries, result.end ());
974void TextInteractor::OnSpellCheckCommand ()
976 if (GetSpellCheckEngine () ==
nullptr) {
980 MyCallback cb (*
this);
981 GetDialogSupport ().DisplaySpellCheckDialog (cb);
985void TextInteractor::OnUpdateSpellCheckCommand (CommandUpdater* enabler)
988 enabler->SetEnabled (GetSpellCheckEngine () !=
nullptr);
999void TextInteractor::SetDefaultUpdateMode (UpdateMode defaultUpdateMode)
1001 if (defaultUpdateMode != eDefaultUpdate) {
1002 fDefaultUpdateMode = defaultUpdateMode;
1017bool TextInteractor::LooksLikeSmartPastableText ([[maybe_unused]]
const Led_tChar* text,
size_t , SmartCNPInfo* smartCNPInfo)
const
1021 if (GetSmartCutAndPasteMode ()) {
1022 size_t selStart = GetSelectionStart ();
1023 size_t selEnd = GetSelectionEnd ();
1026 if (selStart == 0 or selStart >= GetEnd ()) {
1027 smartCNPInfo->fWordBreakAtSelStart =
true;
1030 size_t prev = FindPreviousCharacter (selStart);
1032 CopyOut (prev, 1, &prevC);
1034 CopyOut (selStart, 1, &c);
1035 smartCNPInfo->fWordBreakAtSelStart = (IsShouldBeSepWithWhitespaceWordChar (c) != IsShouldBeSepWithWhitespaceWordChar (prevC));
1038 if (selEnd == 0 or selEnd >= GetEnd ()) {
1039 smartCNPInfo->fWordBreakAtSelEnd =
true;
1042 size_t prev = FindPreviousCharacter (selEnd);
1044 CopyOut (prev, 1, &prevC);
1046 CopyOut (selEnd, 1, &c);
1047 smartCNPInfo->fWordBreakAtSelEnd = (IsShouldBeSepWithWhitespaceWordChar (c) != IsShouldBeSepWithWhitespaceWordChar (prevC));
1067void TextInteractor::OptionallyAddExtraSpaceForSmartCutAndPasteModeAdds (
size_t selStart,
const SmartCNPInfo& smartCNPInfo)
1069 size_t selEnd = GetSelectionEnd ();
1071 Require (0 <= selStart);
1072 Require (selStart <= selEnd);
1073 Require (selEnd <= GetTextStore ().GetEnd ());
1075 if (GetSmartCutAndPasteMode ()) {
1076 if (selEnd > 0 and selEnd < GetTextStore ().GetEnd ()) {
1077 size_t prev = FindPreviousCharacter (selEnd);
1079 CopyOut (prev, 1, &prevC);
1081 CopyOut (selEnd, 1, &c);
1082 if (smartCNPInfo.fWordBreakAtSelEnd and IsShouldBeSepWithWhitespaceWordChar (c) and IsShouldBeSepWithWhitespaceWordChar (prevC)) {
1083 InteractiveReplace_ (selEnd, selEnd, LED_TCHAR_OF (
" "), 1,
false);
1092 SetSelection (selEnd, selEnd);
1096 if (selStart > 0 and selStart < GetTextStore ().GetEnd ()) {
1097 size_t prev = FindPreviousCharacter (selStart);
1099 CopyOut (prev, 1, &prevC);
1101 CopyOut (selStart, 1, &c);
1102 if (smartCNPInfo.fWordBreakAtSelStart and IsShouldBeSepWithWhitespaceWordChar (c) and IsShouldBeSepWithWhitespaceWordChar (prevC)) {
1108 InteractiveReplace_ (selStart, selStart, LED_TCHAR_OF (
" "), 1,
false);
1111 if (IsSmartSpace (c) and IsSmartSpace (prevC)) {
1112 InteractiveReplace_ (selStart, FindNextCharacter (selStart),
nullptr, 0,
false);
1123void TextInteractor::OptionallyExpandSelectionForSmartCutAndPasteModeDeletes (
size_t* selStart,
size_t* selEnd)
1127 Require (0 <= *selStart);
1128 Require (*selStart <= *selEnd);
1129 Require (*selEnd <= GetTextStore ().GetEnd ());
1131 if (GetSmartCutAndPasteMode ()) {
1132 size_t realStart = *selStart;
1133 size_t realEnd = *selEnd;
1134 size_t newStart = realStart;
1135 size_t newEnd = realEnd;
1141 if (realStart < GetEnd ()) {
1143 CopyOut (realStart, 1, &c);
1147 if (realStart > 0) {
1148 CopyOut (FindPreviousCharacter (realStart), 1, &c);
1149 if (IsShouldBeSepWithWhitespaceWordChar (c)) {
1155 if (realStart < realEnd and realEnd < GetEnd ()) {
1157 CopyOut (FindPreviousCharacter (realEnd), 1, &c);
1161 if (realEnd < GetEnd ()) {
1162 CopyOut (realEnd, 1, &c);
1163 if (IsShouldBeSepWithWhitespaceWordChar (c)) {
1175 size_t prev = FindPreviousCharacter (newStart);
1176 CopyOut (prev, 1, &c);
1177 size_t prevprev = FindPreviousCharacter (prev);
1178 Led_tChar prevprevC;
1179 CopyOut (prevprev, 1, &prevprevC);
1180 if (prevprev != prev and IsSmartSpace (c) and not(IsSmartSpace (prevprevC) or prevprevC ==
'\n')) {
1187 if (newEnd < GetEnd ()) {
1188 CopyOut (newEnd, 1, &c);
1189 Led_tChar charBeforeStart =
'\0';
1190 if (newStart != 0) {
1191 CopyOut (FindPreviousCharacter (newStart), 1, &charBeforeStart);
1193 if (IsSmartSpace (c)) {
1194 Assert (newEnd < FindNextCharacter (newEnd));
1195 newEnd = FindNextCharacter (newEnd);
1196 if (newEnd < GetEnd ()) {
1198 Led_tChar nextChar =
'\0';
1199 CopyOut (newEnd, 1, &nextChar);
1200 if (IsShouldBeSepWithWhitespaceWordChar (charBeforeStart) and IsShouldBeSepWithWhitespaceWordChar (nextChar)) {
1201 newEnd = FindPreviousCharacter (newEnd);
1208 *selStart = newStart;
1218void TextInteractor::SetSelectionShown (
bool shown)
1220 SetSelectionShown (shown, eDefaultUpdate);
1223void TextInteractor::SetSelectionShown (
bool shown, UpdateMode updateMode)
1225 if (GetSelectionShown () != shown) {
1226 TextImager::SetSelectionShown (shown);
1227 Refresh (GetSelectionStart (), GetSelectionEnd (), updateMode);
1235void TextInteractor::SetSelection (
size_t start,
size_t end)
1237 Assert (end <= GetEnd ());
1238 UpdateMode updateMode = GetDefaultUpdateMode ();
1241 if (start != GetSelectionStart () or end != GetSelectionEnd ()) {
1242 IdleManager::NonIdleContext nonIdleContext;
1244 size_t oldSelectionStart = GetSelectionStart ();
1245 size_t oldSelectionEnd = GetSelectionEnd ();
1252 if (start == GetSelectionStart ()) {
1253 fLeftSideOfSelectionInteresting =
false;
1255 else if (end == GetSelectionEnd ()) {
1256 fLeftSideOfSelectionInteresting =
true;
1258 else if ((start < GetSelectionStart ()) == (end < GetSelectionEnd ())) {
1259 fLeftSideOfSelectionInteresting = (start < GetSelectionStart ());
1266 InvalidateCaretState ();
1268 TextImager::SetSelection (start, end);
1270 if ((GetSelectionShown () or GetUseSecondaryHilight ()) and updateMode != eNoUpdate) {
1278 UpdateMode useUpdateMode = (updateMode == eImmediateUpdate) ? eDelayedUpdate : updateMode;
1280 size_t lhsOuter = min (oldSelectionStart, GetSelectionStart ());
1281 size_t rhsOuter = max (oldSelectionEnd, GetSelectionEnd ());
1282 size_t lhsInner = max (oldSelectionStart, GetSelectionStart ());
1283 size_t rhsInner = min (oldSelectionEnd, GetSelectionEnd ());
1284 Assert (lhsOuter <= rhsOuter);
1285 Assert (lhsOuter <= lhsInner);
1286 Assert (lhsOuter <= rhsInner);
1287 Assert (lhsOuter <= rhsOuter);
1288 Assert (lhsInner <= rhsOuter);
1289 Assert (rhsInner <= rhsOuter);
1295 Refresh (FindPreviousCharacter (lhsOuter), FindNextCharacter (lhsInner), useUpdateMode);
1296 Refresh (FindPreviousCharacter (rhsInner), FindNextCharacter (rhsOuter), useUpdateMode);
1299 InvalidateCaretState ();
1301 if (updateMode == eImmediateUpdate) {
1304 RecomputeSelectionGoalColumn ();
1307void TextInteractor::SetSelection (
size_t start,
size_t end, UpdateMode updateMode)
1309 TemporarilySetUpdateMode updateModeSetter (*
this, updateMode);
1310 TextImager* tim =
this;
1311 tim->SetSelection (start, end);
1325void TextInteractor::ScrollToSelection (UpdateMode updateMode,
bool forceShowSelectionEndpoint)
1327 size_t selStart = GetSelectionStart ();
1328 size_t selEnd = GetSelectionEnd ();
1338 if (not forceShowSelectionEndpoint and selStart <= GetMarkerPositionOfStartOfWindow () and selEnd >= GetMarkerPositionOfEndOfWindow ()) {
1360 size_t firstCharShown = selStart;
1361 size_t lastCharShown = FindPreviousCharacter (selEnd);
1362 if (fLeftSideOfSelectionInteresting) {
1363 if (firstCharShown != lastCharShown and GetStartOfRowContainingPosition (firstCharShown) != GetStartOfRowContainingPosition (lastCharShown)) {
1364 lastCharShown = firstCharShown;
1366 ScrollSoShowing (firstCharShown, lastCharShown, updateMode);
1369 if (GetCaretShownAfterPos ()) {
1370 lastCharShown = FindNextCharacter (lastCharShown);
1372 if (firstCharShown != lastCharShown and GetStartOfRowContainingPosition (firstCharShown) != GetStartOfRowContainingPosition (lastCharShown)) {
1373 firstCharShown = lastCharShown;
1375 ScrollSoShowing (lastCharShown, firstCharShown, updateMode);
1379void TextInteractor::HookLosingTextStore ()
1381 HookLosingTextStore_ ();
1382 TextImager::HookLosingTextStore ();
1385void TextInteractor::HookLosingTextStore_ ()
1387 AbortReplace (fTmpPreReplaceInfo);
1388 fExternalizer.reset ();
1389 fInternalizer.reset ();
1392void TextInteractor::HookGainedNewTextStore ()
1394 HookGainedNewTextStore_ ();
1395 TextImager::HookGainedNewTextStore ();
1398void TextInteractor::HookGainedNewTextStore_ ()
1400 if (fExternalizer.get () ==
nullptr) {
1401 SetExternalizer (MakeDefaultExternalizer ());
1403 if (fInternalizer.get () ==
nullptr) {
1404 SetInternalizer (MakeDefaultInternalizer ());
1422bool TextInteractor::ProcessSimpleClick (Led_Point clickedAt,
unsigned clickCount,
bool extendSelection,
size_t* dragAnchor)
1425 switch (clickCount) {
1427 size_t newPos = GetCharAtClickLocation (clickedAt);
1428 size_t newSelStart = newPos;
1429 size_t newSelEnd = newPos;
1431 WhileTrackingConstrainSelection (&newSelStart, &newSelEnd);
1432 newPos = newSelStart;
1434 if (extendSelection) {
1435 newSelStart = min (newSelStart, GetSelectionStart ());
1436 newSelEnd = max (newSelEnd, GetSelectionEnd ());
1448 if (extendSelection) {
1450 if (newPos == newSelStart) {
1451 *dragAnchor = newSelEnd;
1454 *dragAnchor = newSelStart;
1458 *dragAnchor = newPos;
1462 if (not extendSelection) {
1463 SetCaretShownAfterPos (GetCharWindowLocation (newPos).top <= clickedAt.v);
1466 WhileTrackingConstrainSelection (&newSelStart, &newSelEnd);
1467 SetSelection (newSelStart, newSelEnd);
1475 DbgTrace (
"TextInteractor::ProcessSimpleClick (tickCount=%f, newMousePos=(%d,%d), clickCount=%d, extendSel=%d, newSelStart=%d, newSelEnd=%d)\n",
1476 Time::GetTickCount (), clickedAt.v, clickedAt.h, clickCount, extendSelection, GetSelectionStart (), GetSelectionEnd ()
1486void TextInteractor::UpdateClickCount (
Time::TimePointSeconds clickAtTime,
const Led_Point& clickAtLocation)
1488 if (ClickTimesAreCloseForDoubleClick (clickAtTime) and PointsAreCloseForDoubleClick (clickAtLocation)) {
1489 IncrementCurClickCount (clickAtTime);
1492 SetCurClickCount (1, clickAtTime);
1494 fLastMouseDownAt = clickAtLocation;
1503 return (fLastClickedAt + Led_GetDoubleClickTime () >= thisClick);
1510bool TextInteractor::PointsAreCloseForDoubleClick (
const Led_Point& p)
1512 const CoordinateType kMultiClickDistance = 4;
1513 CoordinateType hDelta = p.h - fLastMouseDownAt.h;
1517 CoordinateType vDelta = p.v - fLastMouseDownAt.v;
1521 return ((hDelta <= kMultiClickDistance) and (vDelta <= kMultiClickDistance));
1529void TextInteractor::WhileSimpleMouseTracking (Led_Point newMousePos,
size_t dragAnchor)
1531#if qDynamiclyChooseAutoScrollIncrement
1535 bool firstClick = (now - sLastTimeThrough > kClickThreshold);
1537 int increment = firstClick ? 1 : 2;
1539 const int increment = 1;
1542 size_t rhsPos = GetCharAtClickLocation (newMousePos);
1544 size_t ignored = rhsPos;
1545 WhileTrackingConstrainSelection (&rhsPos, &ignored);
1551 if (rhsPos < GetMarkerPositionOfStartOfWindow ()) {
1552 ScrollByIfRoom (-1, eImmediateUpdate);
1553 rhsPos = GetMarkerPositionOfStartOfWindow ();
1555 else if (rhsPos > GetMarkerPositionOfEndOfWindow ()) {
1556 ScrollByIfRoom (1, eImmediateUpdate);
1557 rhsPos = FindNextCharacter (GetMarkerPositionOfEndOfWindow ());
1563 const int kHScrollIncrementFactor = 4;
1564 if (newMousePos.h < GetWindowRect ().left) {
1565 if (GetHScrollPos () > 0) {
1566 SetHScrollPos (max (0,
int (GetHScrollPos ()) - increment * kHScrollIncrementFactor));
1569 else if (newMousePos.h > GetWindowRect ().right) {
1570 SetHScrollPos (min (
static_cast<CoordinateType
> (GetHScrollPos () + increment * kHScrollIncrementFactor),
1571 static_cast<CoordinateType
> (ComputeMaxHScrollPos ())));
1574 size_t newSelStart = min (rhsPos, dragAnchor);
1575 size_t newSelEnd = max (rhsPos, dragAnchor);
1576 WhileTrackingConstrainSelection (&newSelStart, &newSelEnd);
1577 SetSelection (newSelStart, newSelEnd, eImmediateUpdate);
1579#if qDynamiclyChooseAutoScrollIncrement
1580 sLastTimeThrough = now;
1594void TextInteractor::WhileTrackingConstrainSelection (
size_t* selStart,
size_t* selEnd)
1598 Require (GetCurClickCount () > 0);
1599 switch (GetCurClickCount ()) {
1605 WhileTrackingConstrainSelection_ForWholeWords (selStart, selEnd);
1610 WhileTrackingConstrainSelection_ForWholeRows (selStart, selEnd);
1619void TextInteractor::WhileTrackingConstrainSelection_ForWholeWords (
size_t* selStart,
size_t* selEnd)
1624 size_t wordStart = 0;
1626 bool wordReal =
false;
1627 GetTextStore ().FindWordBreaks (*selStart, &wordStart, &wordEnd, &wordReal);
1628 *selStart = wordStart;
1630 GetTextStore ().FindWordBreaks (*selEnd, &wordStart, &wordEnd, &wordReal);
1631#if qDoubleClickSelectsSpaceAfterWord
1634 size_t xWordStart = 0;
1635 size_t xWordEnd = 0;
1636 bool xWordReal =
false;
1637 GetTextStore ().FindWordBreaks (wordEnd, &xWordStart, &xWordEnd, &xWordReal);
1638 if (not xWordReal) {
1650void TextInteractor::WhileTrackingConstrainSelection_ForWholeRows (
size_t* selStart,
size_t* selEnd)
1654 Require (*selStart <= *selEnd);
1656 size_t origSelStart = *selStart;
1657 size_t origSelEnd = *selEnd;
1659 *selStart = GetStartOfRowContainingPosition (origSelStart);
1660 *selEnd = GetStartOfNextRowFromRowContainingPosition (*selEnd);
1662 if (*selEnd <= origSelEnd) {
1663 *selEnd = GetEndOfRowContainingPosition (origSelEnd);
1676size_t TextInteractor::GetCharAtClickLocation (
const Led_Point& where)
const
1678 size_t clickedOnChar = GetCharAtWindowLocation (where);
1679 size_t endOfClickedRow = GetEndOfRowContainingPosition (clickedOnChar);
1692 if (GetEndOfRowContainingPosition (FindPreviousCharacter (clickedOnChar)) == clickedOnChar) {
1693 endOfClickedRow = clickedOnChar;
1696 Assert (GetStartOfRowContainingPosition (clickedOnChar) <= clickedOnChar);
1697 Assert (clickedOnChar <= endOfClickedRow);
1699 if (clickedOnChar < endOfClickedRow) {
1700 Led_Rect charRect = GetCharWindowLocation (clickedOnChar);
1701 bool clickedToLHSOfChar = (where.h <= charRect.left + CoordinateType (charRect.GetWidth ()) / 2 and charRect.GetWidth () != 0);
1702 if (GetTextDirection (clickedOnChar) == eLeftToRight) {
1703 if (not clickedToLHSOfChar) {
1704 clickedOnChar = FindNextCharacter (clickedOnChar);
1708 if (clickedToLHSOfChar) {
1709 clickedOnChar = FindNextCharacter (clickedOnChar);
1713 return (clickedOnChar);
1716void TextInteractor::Draw (
const Led_Rect& ,
bool )
1718 NoteWindowPartiallyUpdated ();
1722void TextInteractor::DrawBefore (
const Led_Rect& ,
bool )
1726 if (not fScrollBarParamsValid) {
1727 UpdateScrollBars ();
1731void TextInteractor::DrawAfter (
const Led_Rect& ,
bool printing)
1733 if (GetUseSecondaryHilight () and not GetSelectionShown () and not printing) {
1735 GetSelectionWindowRegion (&r, GetSelectionStart (), GetSelectionEnd ());
1736 Tablet_Acquirer tablet_ (
this);
1737 Tablet* tablet = tablet_;
1738 tablet->FrameRegion (r, Led_GetSelectedTextBackgroundColor ());
1742void TextInteractor::SetTopRowInWindow (
size_t newTopRow, UpdateMode updateMode)
1744 TemporarilySetUpdateMode updateModeSetter (*
this, updateMode);
1745 TextImager* tim =
this;
1746 tim->SetTopRowInWindow (newTopRow);
1749void TextInteractor::ScrollByIfRoom (ptrdiff_t downBy, UpdateMode updateMode)
1751 TemporarilySetUpdateMode updateModeSetter (*
this, updateMode);
1752 TextImager* tim =
this;
1753 tim->ScrollByIfRoom (downBy);
1756void TextInteractor::ScrollSoShowing (
size_t markerPos,
size_t andTryToShowMarkerPos, UpdateMode updateMode)
1758 TemporarilySetUpdateMode updateModeSetter (*
this, updateMode);
1759 TextImager* tim =
this;
1760 tim->ScrollSoShowing (markerPos, andTryToShowMarkerPos);
1763void TextInteractor::SetDefaultFont (
const IncrementalFontSpecification& defaultFont, UpdateMode updateMode)
1765 TemporarilySetUpdateMode updateModeSetter{*
this, updateMode};
1766 TextImager* tim =
this;
1767 tim->SetDefaultFont (defaultFont);
1771void TextInteractor::SetWindowRect (
const Led_Rect& windowRect, UpdateMode updateMode)
1773 TemporarilySetUpdateMode updateModeSetter (*
this, updateMode);
1774 TextImager* tim =
this;
1775 tim->SetWindowRect (windowRect);
1778void TextInteractor::SetHScrollPos (CoordinateType hScrollPos)
1780 PreScrollInfo preScrollInfo;
1781 PreScrollHelper (eDefaultUpdate, &preScrollInfo);
1782 TextImager::SetHScrollPos (hScrollPos);
1783 PostScrollHelper (preScrollInfo);
1786void TextInteractor::SetHScrollPos (CoordinateType hScrollPos, UpdateMode updateMode)
1788 TemporarilySetUpdateMode updateModeSetter (*
this, updateMode);
1789 TextImager* tim =
this;
1790 tim->SetHScrollPos (hScrollPos);
1793void TextInteractor::PreScrollHelper (UpdateMode updateMode, PreScrollInfo* preScrollInfo)
1795 UpdateMode realUpdateMode = RealUpdateMode (updateMode);
1796 preScrollInfo->fUpdateMode = realUpdateMode;
1797 if (realUpdateMode != eNoUpdate) {
1798 preScrollInfo->fOldWindowStart = GetMarkerPositionOfStartOfWindow ();
1799 preScrollInfo->fOldHScrollPos = GetHScrollPos ();
1800 preScrollInfo->fTryTodoScrollbits = GetUseBitmapScrollingOptimization () and
bool (realUpdateMode == eImmediateUpdate);
1801 if (preScrollInfo->fTryTodoScrollbits) {
1802 preScrollInfo->fOldLastRowStart = GetMarkerPositionOfStartOfLastRowOfWindow ();
1808 preScrollInfo->fTryTodoScrollbits =
false;
1814void TextInteractor::PostScrollHelper (PreScrollInfo preScrollInfo)
1819 size_t newStartOfWindow = GetMarkerPositionOfStartOfWindow ();
1820 preScrollInfo.fUpdateMode = RealUpdateMode (preScrollInfo.fUpdateMode);
1821 if (preScrollInfo.fUpdateMode != eNoUpdate and
1822 ((preScrollInfo.fOldWindowStart != newStartOfWindow) or (preScrollInfo.fOldHScrollPos != GetHScrollPos ()))) {
1825 if (preScrollInfo.fTryTodoScrollbits and preScrollInfo.fOldHScrollPos == GetHScrollPos ()) {
1826 Led_Rect windowRect = GetWindowRect ();
1828 Tablet_Acquirer tablet_{
this};
1829 Tablet* tablet = tablet_;
1830 if (preScrollInfo.fOldWindowStart > newStartOfWindow) {
1836 CoordinateType newPos = GetCharWindowLocation (GetStartOfRowContainingPosition (preScrollInfo.fOldWindowStart)).top;
1839 tablet->ScrollBitsAndInvalRevealed (windowRect, newPos - windowRect.top);
1843 preScrollInfo.fTryTodoScrollbits =
false;
1847 preScrollInfo.fTryTodoScrollbits =
false;
1849 if (preScrollInfo.fTryTodoScrollbits) {
1864 CoordinateType lastRowBottom = GetCharWindowLocation (GetMarkerPositionOfStartOfLastRowOfWindow ()).bottom;
1865 Led_Rect eraser = windowRect;
1866 eraser.top = lastRowBottom;
1867 RefreshWindowRect (eraser, preScrollInfo.fUpdateMode);
1877 CoordinateType newPos = GetCharLocationRowRelativeByPosition (newStartOfWindow, preScrollInfo.fOldWindowStart, 5).top;
1881 tablet->ScrollBitsAndInvalRevealed (windowRect, -newPos);
1885 preScrollInfo.fTryTodoScrollbits =
false;
1889 preScrollInfo.fTryTodoScrollbits =
false;
1892 if (preScrollInfo.fTryTodoScrollbits) {
1896 CoordinateType lastRowBottom = GetCharWindowLocation (preScrollInfo.fOldLastRowStart).bottom;
1897 Led_Rect eraser = windowRect;
1898 eraser.top = lastRowBottom;
1899 RefreshWindowRect (eraser, eDelayedUpdate);
1902 if (preScrollInfo.fUpdateMode == eImmediateUpdate) {
1909 if (preScrollInfo.fTryTodoScrollbits) {
1914 Refresh (preScrollInfo.fUpdateMode);
1918void TextInteractor::Replace (
size_t from,
size_t to,
const Led_tChar* withWhat,
size_t withWhatCharCount, UpdateMode updateMode)
1920 if (from != to or withWhatCharCount != 0) {
1921 Assert (fDoingUpdateModeReplaceOn ==
nullptr);
1922 fDoingUpdateModeReplaceOn =
this;
1924 PreReplaceInfo preReplaceInfo;
1925 PreReplace (from, to, withWhatCharCount, updateMode, &preReplaceInfo);
1926 GetTextStore ().Replace (from, to, withWhat, withWhatCharCount);
1927 PostReplace (preReplaceInfo);
1928 Assert (fDoingUpdateModeReplaceOn ==
this);
1931 Assert (fDoingUpdateModeReplaceOn ==
this);
1932 fDoingUpdateModeReplaceOn =
nullptr;
1935 fDoingUpdateModeReplaceOn =
nullptr;
1939void TextInteractor::AboutToUpdateText (
const MarkerOwner::UpdateInfo& updateInfo)
1941 TextImager::AboutToUpdateText (updateInfo);
1942 if (fDoingUpdateModeReplaceOn !=
this) {
1946 PreReplace (updateInfo.fReplaceFrom, min (updateInfo.fReplaceTo, GetEnd ()), updateInfo.fTextLength, eDefaultUpdate, &fTmpPreReplaceInfo);
1950void TextInteractor::DidUpdateText (
const UpdateInfo& updateInfo)
noexcept
1952 TextImager::DidUpdateText (updateInfo);
1953 if (fDoingUpdateModeReplaceOn !=
this) {
1955 PostReplace (fTmpPreReplaceInfo);
1963void TextInteractor::PreReplace (
size_t from,
size_t to,
size_t withWhatCharCount, UpdateMode updateMode, PreReplaceInfo* preReplaceInfo)
1967 if (preReplaceInfo->fTextInteractor !=
nullptr) {
1968 AbortReplace (*preReplaceInfo);
1971 updateMode = RealUpdateMode (updateMode);
1973 preReplaceInfo->fFrom = from;
1974 preReplaceInfo->fTo = to;
1975 preReplaceInfo->fWithWhatCharCount = withWhatCharCount;
1976 preReplaceInfo->fUpdateMode = updateMode;
1978 if (updateMode == eNoUpdate) {
1982 if (updateMode == eDelayedUpdate and IsWholeWindowInvalid ()) {
1983 preReplaceInfo->fUpdateMode = eNoUpdate;
2002 size_t endOfWindow = GetMarkerPositionOfEndOfWindow ();
2003 if (from > endOfWindow) {
2008 size_t endOfNextRow = GetEndOfRowContainingPosition (FindNextCharacter (endOfWindow));
2009 if (from > endOfNextRow) {
2010 updateMode = eNoUpdate;
2011 preReplaceInfo->fUpdateMode = eNoUpdate;
2017 Assert (updateMode != eNoUpdate);
2029 size_t startPositionOfRowWhereReplaceBegins = GetStartOfRowContainingPosition (from);
2030 size_t startPositionOfRowAfterReplaceEnds = GetEndOfRowContainingPosition (to);
2031 if (startPositionOfRowAfterReplaceEnds < GetTextStore ().GetEnd ()) {
2032 startPositionOfRowAfterReplaceEnds = GetStartOfRowContainingPosition (FindNextCharacter (startPositionOfRowAfterReplaceEnds));
2033 Assert (GetEndOfRowContainingPosition (to) <= startPositionOfRowAfterReplaceEnds);
2035 Assert (startPositionOfRowWhereReplaceBegins <= startPositionOfRowAfterReplaceEnds);
2037 preReplaceInfo->fBoundingUpdateHeight =
2038 GetTextWindowBoundingRect (startPositionOfRowWhereReplaceBegins, startPositionOfRowAfterReplaceEnds).GetHeight ();
2045 size_t expandedFromMarkerPos = 0;
2046 size_t expandedToMarkerPos = 0;
2047 GetStableTypingRegionContaingMarkerRange (from, to, &expandedFromMarkerPos, &expandedToMarkerPos);
2048 if (expandedFromMarkerPos == startPositionOfRowWhereReplaceBegins and expandedToMarkerPos == startPositionOfRowAfterReplaceEnds) {
2050 preReplaceInfo->fStableTypingRegionHeight = preReplaceInfo->fBoundingUpdateHeight;
2051 Assert (preReplaceInfo->fStableTypingRegionHeight == GetTextWindowBoundingRect (expandedFromMarkerPos, expandedToMarkerPos).GetHeight ());
2054 preReplaceInfo->fStableTypingRegionHeight = GetTextWindowBoundingRect (expandedFromMarkerPos, expandedToMarkerPos).GetHeight ();
2062 GetTextStore ().AddMarker (&preReplaceInfo->fBoundingUpdateMarker, startPositionOfRowWhereReplaceBegins,
2063 (startPositionOfRowAfterReplaceEnds - startPositionOfRowWhereReplaceBegins) + 1,
this);
2064 preReplaceInfo->fTextInteractor =
this;
2066 catch (NotFullyInitialized&) {
2068 preReplaceInfo->fUpdateMode = eNoUpdate;
2076void TextInteractor::PostReplace (PreReplaceInfo& preReplaceInfo)
2078 UpdateMode updateMode = preReplaceInfo.fUpdateMode;
2079 if (updateMode != eNoUpdate) {
2080 size_t from = preReplaceInfo.fFrom;
2081 size_t withWhatCharCount = preReplaceInfo.fWithWhatCharCount;
2083 size_t newTo = from + withWhatCharCount;
2086 size_t startPositionOfRowWhereReplaceBegins = preReplaceInfo.fBoundingUpdateMarker.GetStart ();
2087 size_t startPositionOfRowAfterReplaceEnds = preReplaceInfo.fBoundingUpdateMarker.GetEnd () - 1;
2088 Assert (startPositionOfRowWhereReplaceBegins <= startPositionOfRowAfterReplaceEnds);
2090 size_t stableTypingRegionStart = 0;
2091 size_t stableTypingRegionEnd = 0;
2092 GetStableTypingRegionContaingMarkerRange (from, newTo, &stableTypingRegionStart, &stableTypingRegionEnd);
2094 size_t expandedFromMarkerPos = 0;
2095 size_t expandedToMarkerPos = 0;
2096 ExpandedFromAndToInPostReplace (from, newTo, stableTypingRegionStart, stableTypingRegionEnd, startPositionOfRowWhereReplaceBegins,
2097 startPositionOfRowAfterReplaceEnds, &expandedFromMarkerPos, &expandedToMarkerPos);
2099 Led_Rect windowRect = GetWindowRect ();
2100 Led_Rect expandedFromToMarkerRect = GetTextWindowBoundingRect (expandedFromMarkerPos, expandedToMarkerPos);
2101 Led_Rect updateRect = expandedFromToMarkerRect;
2104 updateRect.right = windowRect.right;
2108 Led_Rect revisedRect = expandedFromToMarkerRect;
2109 if (expandedFromMarkerPos != startPositionOfRowWhereReplaceBegins or expandedToMarkerPos != startPositionOfRowAfterReplaceEnds) {
2110 revisedRect = GetTextWindowBoundingRect (startPositionOfRowWhereReplaceBegins, startPositionOfRowAfterReplaceEnds);
2112 Assert (revisedRect == GetTextWindowBoundingRect (startPositionOfRowWhereReplaceBegins, startPositionOfRowAfterReplaceEnds));
2114 if (preReplaceInfo.fBoundingUpdateHeight != revisedRect.GetHeight ()) {
2115 updateRect = Led_Rect (updateRect.top, windowRect.left, windowRect.bottom - updateRect.top, windowRect.GetWidth ());
2121 Led_Rect revisedRect = expandedFromToMarkerRect;
2122 if (expandedFromMarkerPos != stableTypingRegionStart or expandedToMarkerPos != stableTypingRegionEnd) {
2123 revisedRect = GetTextWindowBoundingRect (stableTypingRegionStart, stableTypingRegionEnd);
2125 Assert (revisedRect == GetTextWindowBoundingRect (stableTypingRegionStart, stableTypingRegionEnd));
2126 if (preReplaceInfo.fStableTypingRegionHeight != revisedRect.GetHeight ()) {
2127 updateRect = Led_Rect (updateRect.top, windowRect.left, windowRect.bottom - updateRect.top, windowRect.GetWidth ());
2131 RefreshWindowRect (updateRect, updateMode);
2135void TextInteractor::AbortReplace (PreReplaceInfo& preReplaceInfo)
2137 if (preReplaceInfo.fTextInteractor !=
nullptr) {
2139 preReplaceInfo.fTextInteractor->GetTextStore ().RemoveMarker (&preReplaceInfo.fBoundingUpdateMarker);
2140 preReplaceInfo.fTextInteractor =
nullptr;
2144void TextInteractor::ExpandedFromAndToInPostReplace (
size_t from,
size_t newTo,
size_t stableTypingRegionStart,
2145 size_t stableTypingRegionEnd,
size_t startPositionOfRowWhereReplaceBegins,
2146 size_t startPositionOfRowAfterReplaceEnds,
size_t* expandedFrom,
size_t* expandedTo)
2156 size_t expandedFromMarkerPos = 0;
2157 if (GetStartOfRowContainingPosition (from) == startPositionOfRowWhereReplaceBegins) {
2158 expandedFromMarkerPos = from;
2164 if (expandedFromMarkerPos > startPositionOfRowWhereReplaceBegins) {
2165 expandedFromMarkerPos = FindPreviousCharacter (expandedFromMarkerPos);
2170 expandedFromMarkerPos = stableTypingRegionStart;
2176 size_t expandedToMarkerPos = GetEndOfRowContainingPosition (newTo);
2178 size_t nowStartOfNextRow = expandedToMarkerPos;
2179 if (nowStartOfNextRow < GetTextStore ().GetEnd ()) {
2180 nowStartOfNextRow = GetStartOfRowContainingPosition (FindNextCharacter (nowStartOfNextRow));
2181 Assert (expandedToMarkerPos <= nowStartOfNextRow);
2184 if (nowStartOfNextRow != startPositionOfRowAfterReplaceEnds) {
2186 expandedToMarkerPos = stableTypingRegionEnd;
2190 *expandedFrom = expandedFromMarkerPos;
2191 *expandedTo = expandedToMarkerPos;
2194void TextInteractor::InteractiveReplace (
const Led_tChar* withWhat,
size_t withWhatCharCount, UpdateMode updateMode)
2196 BreakInGroupedCommandsIfDifferentCommand (GetCommandNames ().fTypingCommandName);
2197 InteractiveModeUpdater iuMode{*
this};
2198 UndoableContextHelper undoContext{*
this, GetCommandNames ().fTypingCommandName, withWhatCharCount == 0};
2200 InteractiveReplace_ (undoContext.GetUndoRegionStart (), undoContext.GetUndoRegionEnd (), withWhat, withWhatCharCount,
true,
true, updateMode);
2201 bool anyChanges = InteractiveReplaceEarlyPostReplaceHook (withWhatCharCount);
2202 if (withWhatCharCount == 1 and not anyChanges) {
2204 undoContext.SetSimplePlainTextInsertOptimization (
true);
2207 undoContext.CommandComplete ();
2214void TextInteractor::InteractiveReplace_ (
size_t from,
size_t to,
const Led_tChar* withWhat,
size_t withWhatCharCount,
2215 bool updateCursorPosition,
bool validateTextForCharsetConformance, UpdateMode updateMode)
2218 if (validateTextForCharsetConformance) {
2220 if (not ValidateTextForCharsetConformance (withWhat, withWhatCharCount)) {
2226 TempMarker newSel{GetTextStore (), to + 1, to + 1};
2232 Tablet_Acquirer performanceHackTablet{
this};
2238 SetCaretShownAfterPos (
true);
2240 Replace (from, to, withWhat, withWhatCharCount, updateMode);
2241 if (updateCursorPosition) {
2242 size_t newSelection = newSel.GetStart ();
2243 if (newSelection > 0) {
2247 SetSelection (newSelection, newSelection);
2262bool TextInteractor::InteractiveReplaceEarlyPostReplaceHook (
size_t )
2279void TextInteractor::PreInteractiveUndoHelper (InteractiveReplaceCommand::SavedTextRep** beforeRep,
size_t regionStart,
size_t regionEnd,
2280 size_t selStart,
size_t selEnd)
2282 Require (regionStart <= regionEnd);
2283 Require (selStart <= selEnd);
2285 Require ((*beforeRep) ==
nullptr);
2289 (*beforeRep) = InteractiveUndoHelperMakeTextRep (regionStart, regionEnd, selStart, selEnd);
2298 fCommandHandler->Commit ();
2313void TextInteractor::PostInteractiveUndoHelper (InteractiveReplaceCommand::SavedTextRep** beforeRep,
size_t startOfInsert,
2314 size_t endOfInsert,
const SDKString& cmdName)
2319 SavedTextRep* afterRep =
nullptr;
2321 afterRep = InteractiveUndoHelperMakeTextRep (startOfInsert, endOfInsert, GetSelectionStart (), GetSelectionEnd ());
2322 PostInteractiveUndoPostHelper (beforeRep, &afterRep, startOfInsert, cmdName);
2325 delete (*beforeRep);
2326 (*beforeRep) =
nullptr;
2338void TextInteractor::PostInteractiveSimpleCharInsertUndoHelper (InteractiveReplaceCommand::SavedTextRep** beforeRep,
size_t startOfInsert,
2339 size_t endOfInsert,
const SDKString& cmdName)
2344 if (endOfInsert - startOfInsert == 1) {
2346 CopyOut (startOfInsert, 1, &c);
2347 if (fCommandHandler->PostUpdateSimpleTextInsert (startOfInsert, c)) {
2349 *beforeRep =
nullptr;
2353 SavedTextRep* afterRep =
new InteractiveReplaceCommand::PlainTextRep (GetSelectionStart (), GetSelectionEnd (), &c, 1);
2354 PostInteractiveUndoPostHelper (beforeRep, &afterRep, startOfInsert, cmdName);
2355 Assert (afterRep ==
nullptr);
2359 PostInteractiveUndoHelper (beforeRep, startOfInsert, endOfInsert, cmdName);
2370void TextInteractor::PostInteractiveUndoPostHelper (InteractiveReplaceCommand::SavedTextRep** beforeRep,
2371 InteractiveReplaceCommand::SavedTextRep** afterRep,
size_t startOfInsert,
const SDKString& cmdName)
2377 if (*beforeRep !=
nullptr and *afterRep !=
nullptr) {
2380 InteractiveReplaceCommand* cmd =
new InteractiveReplaceCommand (*beforeRep, *afterRep, startOfInsert, cmdName);
2381 *beforeRep =
nullptr;
2382 *afterRep =
nullptr;
2383 fCommandHandler->Post (cmd);
2388 *beforeRep =
nullptr;
2390 *afterRep =
nullptr;
2395InteractiveReplaceCommand::SavedTextRep* TextInteractor::InteractiveUndoHelperMakeTextRep (
size_t regionStart,
size_t regionEnd,
2396 size_t selStart,
size_t selEnd)
2398 if (regionStart == regionEnd) {
2400 return new InteractiveReplaceCommand::PlainTextRep (selStart, selEnd,
nullptr, 0);
2403 return new FlavorSavorTextRep (
this, regionStart, regionEnd, selStart, selEnd);
2407void TextInteractor::OnUndoCommand ()
2409 InteractiveModeUpdater iuMode (*
this);
2410 if (GetCommandHandler () !=
nullptr and GetCommandHandler ()->CanUndo ()) {
2411 GetCommandHandler ()->DoUndo (*
this);
2412 ScrollToSelection ();
2419void TextInteractor::OnRedoCommand ()
2421 InteractiveModeUpdater iuMode (*
this);
2422 if (GetCommandHandler () !=
nullptr and GetCommandHandler ()->CanRedo ()) {
2423 GetCommandHandler ()->DoRedo (*
this);
2424 ScrollToSelection ();
2431void TextInteractor::Refresh (
size_t from,
size_t to, UpdateMode updateMode)
const
2433 Require (from <= to);
2434 updateMode = RealUpdateMode (updateMode);
2435 if ((updateMode != eNoUpdate) and (from != to)) {
2436 if (updateMode == eDelayedUpdate and IsWholeWindowInvalid ()) {
2444 Led_Rect refreshRect = GetTextWindowBoundingRect (from, to);
2445 RefreshWindowRect_ (refreshRect, updateMode);
2449void TextInteractor::Refresh (
const Marker* range, UpdateMode updateMode)
const
2452 updateMode = RealUpdateMode (updateMode);
2453 if (updateMode != eNoUpdate) {
2454 if (updateMode == eDelayedUpdate and IsWholeWindowInvalid ()) {
2457 Refresh (range->GetStart (), range->GetEnd (), updateMode);
2466void TextInteractor::DoSingleCharCursorEdit (CursorMovementDirection direction, CursorMovementUnit movementUnit,
2467 CursorMovementAction action, UpdateMode updateMode,
bool scrollToSelection)
2469 IdleManager::NonIdleContext nonIdleContext;
2471 size_t oldStartSel = GetSelectionStart ();
2472 size_t oldEndSel = GetSelectionEnd ();
2473 Assert (GetSelectionEnd () <= GetLength () + 1);
2475 size_t newStartSel = oldStartSel;
2476 size_t newEndSel = oldEndSel;
2478 UpdateMode useUpdateMode = (updateMode == eImmediateUpdate) ? eDelayedUpdate : updateMode;
2480 GoalColumnRecomputerControlContext skipRecompute (*
this, action == eCursorMoving and movementUnit == eCursorByRow and
2481 (direction == eCursorBack or direction == eCursorForward));
2492 if (movementUnit == eCursorByRow and GetStartOfRowContainingPosition (newStartSel) == newStartSel) {
2493 if (GetCaretShownAfterPos ()) {
2494 if (direction == eCursorToEnd and GetEndOfRowContainingPosition (newStartSel) == newStartSel) {
2495 goto SkipNavigation;
2499 if (direction == eCursorToStart) {
2502 newStartSel = FindPreviousCharacter (newStartSel);
2504 if (direction == eCursorToEnd) {
2505 goto SkipNavigation;
2513 if (movementUnit == eCursorByChar) {
2514 SetCaretShownAfterPos (
true);
2516 if (movementUnit == eCursorByRow) {
2517 switch (direction) {
2518 case eCursorToStart:
2519 SetCaretShownAfterPos (
true);
2522 SetCaretShownAfterPos (
false);
2527 if (action != eCursorExtendingSelection or (oldStartSel == oldEndSel)) {
2528 fLeftSideOfSelectionInteresting = (direction == eCursorBack or direction == eCursorToStart);
2530 if (fLeftSideOfSelectionInteresting) {
2531 newStartSel = ComputeRelativePosition (newStartSel, direction, movementUnit);
2532 if (action == eCursorMoving) {
2533 newEndSel = newStartSel;
2537 newEndSel = ComputeRelativePosition (newEndSel, direction, movementUnit);
2538 if (action == eCursorMoving) {
2539 newStartSel = newEndSel;
2546 if (newEndSel < newStartSel) {
2547 size_t tmp = newStartSel;
2548 newStartSel = newEndSel;
2551 Assert (newStartSel <= newEndSel);
2557 case eCursorDestroying: {
2558 if (oldStartSel == oldEndSel) {
2563 Assert (newEndSel >= newStartSel);
2564 size_t howMany = newEndSel - newStartSel;
2566 bool oldCutAndPaste = GetSmartCutAndPasteMode ();
2568 SetSmartCutAndPasteMode (
false);
2570 BreakInGroupedCommandsIfDifferentCommand (GetCommandNames ().fClearCommandName);
2571 InteractiveModeUpdater iuMode (*
this);
2572 UndoableContextHelper undoContext (*
this, GetCommandNames ().fClearCommandName, newStartSel, newEndSel,
2573 GetSelectionStart (), GetSelectionEnd (),
true);
2575 InteractiveReplace_ (undoContext.GetUndoRegionStart (), undoContext.GetUndoRegionEnd (), LED_TCHAR_OF (
""),
2576 0,
true,
true, useUpdateMode);
2578 undoContext.CommandComplete ();
2583 GetSelection (&newStartSel, &newEndSel);
2584 SetSmartCutAndPasteMode (oldCutAndPaste);
2587 SetSmartCutAndPasteMode (oldCutAndPaste);
2599 Assert (oldEndSel >= oldStartSel);
2600 Assert (oldStartSel == GetSelectionStart ());
2601 Assert (oldEndSel == GetSelectionEnd ());
2606 GetSelection (&newStartSel, &newEndSel);
2610 case eCursorMoving: {
2614 case eCursorExtendingSelection: {
2628 SetSelection (newStartSel, newEndSel, useUpdateMode);
2630 if (scrollToSelection) {
2631 ScrollToSelection (useUpdateMode,
true);
2634 if (updateMode == eImmediateUpdate) {
2639void TextInteractor::OnCutCommand ()
2641 InteractiveModeUpdater iuMode (*
this);
2642 BreakInGroupedCommands ();
2643 if (GetSelectionStart () != GetSelectionEnd ()) {
2645 UndoableContextHelper undoContext (*
this, GetCommandNames ().fCutCommandName,
true);
2647 InteractiveReplace_ (undoContext.GetUndoRegionStart (), undoContext.GetUndoRegionEnd (), LED_TCHAR_OF (
""), 0);
2649 undoContext.CommandComplete ();
2651 BreakInGroupedCommands ();
2654void TextInteractor::OnCopyCommand ()
2656 size_t start = GetSelectionStart ();
2657 size_t end = GetSelectionEnd ();
2658 Assert (start <= end);
2660 BreakInGroupedCommands ();
2662 if (OnCopyCommand_Before ()) {
2664 OnCopyCommand_CopyFlavors ();
2667 OnCopyCommand_After ();
2670 OnCopyCommand_After ();
2675void TextInteractor::OnPasteCommand ()
2677 InteractiveModeUpdater iuMode (*
this);
2678 BreakInGroupedCommands ();
2680 if (OnPasteCommand_Before ()) {
2682 UndoableContextHelper undoContext (*
this, GetCommandNames ().fPasteCommandName,
false);
2684 OnPasteCommand_PasteBestFlavor ();
2686 undoContext.CommandComplete ();
2689 OnPasteCommand_After ();
2692 OnPasteCommand_After ();
2694 BreakInGroupedCommands ();
2697void TextInteractor::OnClearCommand ()
2699 InteractiveModeUpdater iuMode (*
this);
2700 BreakInGroupedCommands ();
2701 UndoableContextHelper undoContext (*
this, GetCommandNames ().fClearCommandName,
true);
2703 InteractiveReplace_ (undoContext.GetUndoRegionStart (), undoContext.GetUndoRegionEnd (), LED_TCHAR_OF (
""), 0);
2705 undoContext.CommandComplete ();
2706 BreakInGroupedCommands ();
2722bool TextInteractor::OnCopyCommand_Before ()
2732void TextInteractor::OnCopyCommand_After ()
2741void TextInteractor::OnCopyCommand_CopyFlavors ()
2743 WriterClipboardFlavorPackage writer;
2744 ExternalizeFlavors (writer);
2747bool TextInteractor::ShouldEnablePasteCommand ()
const
2749 return Led_ClipboardObjectAcquire::FormatAvailable_TEXT ();
2764bool TextInteractor::OnPasteCommand_Before ()
2774void TextInteractor::OnPasteCommand_After ()
2783void TextInteractor::OnPasteCommand_PasteBestFlavor ()
2785#if qStroika_Foundation_Common_Platform_Windows && 0
2789 long clipFormat = 0;
2790 while ((clipFormat = ::EnumClipboardFormats (clipFormat)) != 0) {
2792 int nChars = ::GetClipboardFormatName (clipFormat, buf, Memory::NEltsOf (buf));
2797 ReaderClipboardFlavorPackage clipData;
2799 SmartCNPInfo smartCNPInfo;
2800 bool doSmartCNP = PasteLooksLikeSmartCNP (&smartCNPInfo);
2801 size_t savedSelStart = GetSelectionStart ();
2802 InternalizeBestFlavor (clipData);
2803 Assert (savedSelStart <= GetSelectionStart ());
2805 OptionallyAddExtraSpaceForSmartCutAndPasteModeAdds (savedSelStart, smartCNPInfo);
2814void TextInteractor::OnPasteCommand_PasteFlavor_Specific (Led_ClipFormat format)
2816 ReaderClipboardFlavorPackage clipData;
2817 SmartCNPInfo smartCNPInfo;
2818 bool doSmartCNP = PasteLooksLikeSmartCNP (&smartCNPInfo);
2819 size_t savedSelStart = GetSelectionStart ();
2820 InternalizeFlavor_Specific (clipData, format);
2821 Assert (savedSelStart <= GetSelectionStart ());
2823 OptionallyAddExtraSpaceForSmartCutAndPasteModeAdds (savedSelStart, smartCNPInfo);
2832bool TextInteractor::PasteLooksLikeSmartCNP (SmartCNPInfo* scnpInfo)
const
2835 ReaderClipboardFlavorPackage clipData;
2836 bool doSmartCNP = GetSmartCutAndPasteMode () and clipData.GetFlavorAvailable_TEXT ();
2841 size_t length = clipData.GetFlavorSize (kTEXTClipFormat);
2842 Led_ClipFormat textFormat = kTEXTClipFormat;
2845 length = clipData.ReadFlavorData (textFormat, length, buf.data ());
2847 Led_tChar* buffp =
reinterpret_cast<Led_tChar*
> (
static_cast<char*
> (buf));
2848 size_t nTChars = length /
sizeof (Led_tChar);
2849 doSmartCNP = LooksLikeSmartPastableText (buffp, nTChars, scnpInfo);
2860void TextInteractor::OnSelectAllCommand ()
2862 SetSelection (0, GetLength ());
2865bool TextInteractor::CanAcceptFlavor (Led_ClipFormat clipFormat)
const
2867 return (kTEXTClipFormat == clipFormat or kFILEClipFormat == clipFormat);
2870void TextInteractor::InternalizeBestFlavor (
ReaderFlavorPackage& flavorPackage,
bool updateCursorPosition,
bool autoScroll, UpdateMode updateMode)
2872 size_t start = GetSelectionStart ();
2873 size_t end = GetSelectionEnd ();
2877 TempMarker newSel{GetTextStore (), end + 1, end + 1};
2882 good = fInternalizer->InternalizeBestFlavor (flavorPackage, start, end);
2883 if (good and updateCursorPosition) {
2884 SetCaretShownAfterPos (
true);
2889 size_t newSelection = newSel.GetStart ();
2890 if (newSelection > start) {
2894 SetSelection (newSelection, newSelection);
2900 ScrollToSelection ();
2902 if (updateMode == eImmediateUpdate) {
2915void TextInteractor::InternalizeFlavor_Specific (
ReaderFlavorPackage& flavorPackage, Led_ClipFormat format,
bool updateCursorPosition,
2916 bool autoScroll, UpdateMode updateMode)
2918 size_t start = GetSelectionStart ();
2919 size_t end = GetSelectionEnd ();
2923 TempMarker newSel{GetTextStore (), end + 1, end + 1};
2929 if (format == kTEXTClipFormat) {
2930 good = fInternalizer->InternalizeFlavor_TEXT (flavorPackage, start, end);
2932 else if (format == kFILEClipFormat) {
2933 good = fInternalizer->InternalizeFlavor_FILE (flavorPackage, start, end);
2936 good = fInternalizer->InternalizeBestFlavor (flavorPackage, start, end);
2939 if (good and updateCursorPosition) {
2940 SetCaretShownAfterPos (
true);
2945 size_t newSelection = newSel.GetStart ();
2946 if (newSelection > start) {
2950 SetSelection (newSelection, newSelection);
2956 ScrollToSelection ();
2958 if (updateMode == eImmediateUpdate) {
2973shared_ptr<FlavorPackageInternalizer> TextInteractor::MakeDefaultInternalizer ()
2975 return make_shared<FlavorPackageInternalizer> (GetTextStore ());
2982void TextInteractor::HookInternalizerChanged ()
2993 fExternalizer->ExternalizeFlavors (flavorPackage, GetSelectionStart (), GetSelectionEnd ());
3003 fExternalizer->ExternalizeBestFlavor (flavorPackage, GetSelectionStart (), GetSelectionEnd ());
3012shared_ptr<FlavorPackageExternalizer> TextInteractor::MakeDefaultExternalizer ()
3014 return make_shared<FlavorPackageExternalizer> (GetTextStore ());
3021void TextInteractor::HookExternalizerChanged ()
3031void TextInteractor::OnBadUserInput ()
3035 throw BadUserInput{};
3057void TextInteractor::SetScrollBarType (VHSelect vh, ScrollBarType scrollBarType)
3059 if (GetScrollBarType (vh) != scrollBarType) {
3060 InvalidateScrollBarParameters ();
3061 SetScrollBarType_ (vh, scrollBarType);
3070void TextInteractor::InvalidateScrollBarParameters ()
3072 InvalidateScrollBarParameters_ ();
3082void TextInteractor::UpdateScrollBars ()
3084 UpdateScrollBars_ ();
3091void TextInteractor::SetCaretShown (
bool shown)
3093 if (GetCaretShown () != shown) {
3094 fCaretShown = shown;
3095 InvalidateCaretState ();
3096#if qStroika_Foundation_Common_Platform_MacOS
3100 RefreshWindowRect (CalculateCaretRect ());
3114bool TextInteractor::GetCaretShownSituation ()
const
3116 size_t selStart = 0;
3118 GetSelection (&selStart, &selEnd);
3119 return selStart == selEnd;
3126void TextInteractor::SetCaretShownAfterPos (
bool shownAfterPos)
3128 if (GetCaretShownAfterPos () != shownAfterPos) {
3129 InvalidateCaretState ();
3130 fCaretShownAfterPos = shownAfterPos;
3131 InvalidateCaretState ();
3151Led_Rect TextInteractor::CalculateCaretRect ()
const
3153 size_t selEnd = GetSelectionEnd ();
3154 if (GetSelectionStart () == selEnd) {
3155 bool showAfter = GetCaretShownAfterPos ();
3160 size_t charAfterPos = showAfter ? selEnd : FindPreviousCharacter (selEnd);
3161 TextDirection textDirection = GetTextDirection (charAfterPos);
3162 Led_Rect caretRect = GetCharWindowLocation (charAfterPos);
3164 if (caretRect.GetBottom () < GetWindowRect ().GetTop () or caretRect.GetTop () > GetWindowRect ().GetBottom ()) {
3165 return Led_Rect{0, 0, 0, 0};
3168 Led_Rect origCaretRect = caretRect;
3169 FontMetrics fontMetrics = GetFontMetricsAt (charAfterPos);
3172 DistanceType baseLineFromTop = GetRowRelativeBaselineOfRowContainingPosition (charAfterPos);
3173 CoordinateType realBaseLine = baseLineFromTop + caretRect.top;
3176 caretRect.top = realBaseLine - fontMetrics.GetAscent ();
3177 caretRect.bottom = realBaseLine + fontMetrics.GetDescent ();
3182 if (caretRect.top < origCaretRect.top) {
3183 DistanceType diff = origCaretRect.GetTop () - caretRect.GetTop ();
3184 caretRect += Led_Point (diff, 0);
3188 caretRect.SetTop (max (caretRect.GetTop (), origCaretRect.GetTop ()));
3189 caretRect.bottom = min (caretRect.GetBottom (), origCaretRect.GetBottom ());
3191 if (textDirection == eLeftToRight) {
3192 if (not showAfter) {
3193 caretRect.left = caretRect.right;
3197 caretRect.left = caretRect.right;
3200 const CoordinateType kCaretWidth = 1;
3202 const CoordinateType kSluff = kCaretWidth + 1;
3203 if (caretRect.GetLeft () + kSluff > GetWindowRect ().GetRight ()) {
3204 caretRect.SetLeft (GetWindowRect ().GetRight () - kSluff);
3206 caretRect.SetRight (caretRect.GetLeft () + kCaretWidth);
3208 Ensure (not caretRect.IsEmpty ());
3212 return (Led_Rect{0, 0, 0, 0});
3216void TextInteractor::InvalidateCaretState ()
3218 if (IsWholeWindowInvalid ()) {
3221 if (GetCaretShown () and (GetSelectionStart () == GetSelectionEnd ())) {
3222 RefreshWindowRect (CalculateCaretRect ());
3234void TextInteractor::OnTypedNormalCharacter (Led_tChar theChar,
bool ,
bool ,
bool ,
3235 bool controlPressed,
bool )
3237 IdleManager::NonIdleContext nonIdleContext;
3239 Assert (GetSelectionEnd () <= GetLength () + 1);
3241 if (GetSuppressTypedControlCharacters ()) {
3243 if (controlChar && (theChar ==
'\r' || theChar ==
'\n' || theChar ==
' ' || theChar ==
'\t' || theChar ==
'\b')) {
3244 controlChar =
false;
3254 CursorMovementDirection dir = eCursorBack;
3255 CursorMovementUnit unit = controlPressed ? eCursorByWord : eCursorByChar;
3256 CursorMovementAction action = eCursorDestroying;
3257 DoSingleCharCursorEdit (dir, unit, action, eDefaultUpdate);
3261 if (theChar ==
'\n') {
3262 BreakInGroupedCommands ();
3264 InteractiveReplace (&theChar, 1, eDefaultUpdate);
3268 ScrollToSelection ();
3269#if qPeekForMoreCharsOnUserTyping
3270 UpdateIfNoKeysPending ();
3276#if qStroika_Foundation_Common_Platform_MacOS || qStroika_FeatureSupported_XWindows
3277float TextInteractor::GetTickCountBetweenBlinks ()
3279#if qStroika_Foundation_Common_Platform_MacOS
3280 return ::GetCaretTime () / 60.0;
3281#elif qStroika_FeatureSupported_XWindows
3287bool TextInteractor::DelaySomeForScrollBarClick ()
3291 const int kTimesForFirstClick = 2;
3293 static short sTimesThruBeforeReset;
3297 fLastScrolledAt = now + kDelayAfterFirstTicks;
3298 sTimesThruBeforeReset = 1;
3301 else if (fLastScrolledAt < now) {
3302 ++sTimesThruBeforeReset;
3303 fLastScrolledAt = now + (sTimesThruBeforeReset <= kTimesForFirstClick ? kDelayAfterFirstTicks : kDelayAfterOtherTicks);
#define RequireNotNull(p)
time_point< RealtimeClock, DurationSeconds > TimePointSeconds
TimePointSeconds is a simpler approach to chrono::time_point, which doesn't require using templates e...
chrono::duration< double > DurationSeconds
chrono::duration<double> - a time span (length of time) measured in seconds, but high precision.
constexpr bool IsControl() const noexcept
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...
nonvirtual pointer data() noexcept
returns a (possibly const) pointer to the start of the live buffer data. This return value can be inv...
basic_string< SDKChar > SDKString