4#include "Stroika/Frameworks/StroikaPreComp.h"
15#include "Stroika/Frameworks/Led/Command.h"
16#include "Stroika/Frameworks/Led/Config.h"
17#include "Stroika/Frameworks/Led/IdleManager.h"
18#include "Stroika/Frameworks/Led/Marker.h"
19#include "Stroika/Frameworks/Led/TextInteractor.h"
20#include "Stroika/Frameworks/Led/TextStore.h"
25using namespace Stroika::Frameworks;
26using namespace Stroika::Frameworks::Led;
28#if qStroika_Frameworks_Led_SupportGDI
29using SavedTextRep = InteractiveReplaceCommand::SavedTextRep;
32 class FlavorSavorTextRep :
public SavedTextRep {
34 using inherited = SavedTextRep;
37 FlavorSavorTextRep (TextInteractor* interactor,
size_t regionStart,
size_t regionEnd,
size_t selStart,
size_t selEnd)
38 : inherited (selStart, selEnd)
40 , fTextLength (regionEnd - regionStart)
42#if !qFailToLookupFunctionNameWhenCompilingFunctionLocalClassMethodCompilerBug
45 interactor->GetExternalizer ()->ExternalizeBestFlavor (fSavedText, regionStart, regionEnd);
47 virtual size_t GetLength ()
const override
51 virtual void InsertSelf (TextInteractor* interactor,
size_t at,
size_t nBytesToOverwrite)
override
53#if !qFailToLookupFunctionNameWhenCompilingFunctionLocalClassMethodCompilerBug
56 interactor->GetInternalizer ()->InternalizeBestFlavor (fSavedText, at, at + nBytesToOverwrite);
67 inline bool IsSmartSpace (Led_tChar c)
69 return (c ==
' ' or c ==
'\t');
71 inline bool IsShouldBeSepWithWhitespaceWordChar (Led_tChar c)
79 return Character (c).IsAlphaNumeric () and c < 127;
84 class MyCallback :
public TextInteractor::DialogSupport::SpellCheckDialogCallback {
86 using inherited = TextInteractor::DialogSupport::SpellCheckDialogCallback;
89 MyCallback (TextInteractor& ti)
96 DISABLE_COMPILER_MSC_WARNING_START (6262)
97 virtual MisspellingInfo* GetNextMisspelling ()
override
99 SpellCheckEngine* sce = fTI.GetSpellCheckEngine ();
100 if (sce !=
nullptr) {
101 Led_tChar charBuf[10 * 1024];
102 bool firstTry =
true;
103 size_t startRegion = fTI.GetSelectionEnd ();
108 size_t wordStart = 0;
110 bool wordReal =
false;
111 fTI.GetTextStore ().FindWordBreaks (startRegion, &wordStart, &wordEnd, &wordReal, sce->PeekAtTextBreaksUsed ());
112 if (wordReal and wordStart + std::size (charBuf) > startRegion) {
113 startRegion = wordStart;
116 size_t endRegion = min (startRegion + std::size (charBuf), fTI.GetEnd ());
117 fTI.CopyOut (startRegion, endRegion - startRegion, charBuf);
118 const Led_tChar* cursor =
nullptr;
119 const Led_tChar* wordStart =
nullptr;
120 const Led_tChar* wordEnd =
nullptr;
121 if (sce->ScanForUndefinedWord (charBuf, charBuf + (endRegion - startRegion), &cursor, &wordStart, &wordEnd)) {
126 if (wordStart != charBuf and wordEnd == charBuf + (endRegion - startRegion)) {
127 startRegion += (wordStart - charBuf);
131 Led_tString undefinedWord = Led_tString{wordStart, wordEnd};
132 if (fIgnoredWords.find (undefinedWord) != fIgnoredWords.end ()) {
135 startRegion += (wordEnd - charBuf);
138 MisspellingInfo* mi =
new MisspellingInfo ();
139 mi->fUndefinedWord = undefinedWord;
140 mi->fSuggestions = sce->GenerateSuggestions (mi->fUndefinedWord);
141 size_t selStart = startRegion + wordStart - charBuf;
142 size_t selEnd = selStart + (wordEnd - wordStart);
143 fTI.SetSelection (selStart, selEnd);
144 fTI.ScrollToSelection ();
147 else if (endRegion < fTI.GetEnd ()) {
150 startRegion = endRegion;
162 DISABLE_COMPILER_MSC_WARNING_END (6262)
163 virtual
void DoIgnore ()
override
165 fTI.SetSelection (fTI.GetSelectionEnd (), fTI.GetSelectionEnd ());
166 fTI.ScrollToSelection ();
168 virtual void DoIgnoreAll ()
override
171 size_t origSelStart = fTI.GetSelectionStart ();
172 size_t origSelEnd = fTI.GetSelectionEnd ();
174 fTI.CopyOut (origSelStart, origSelEnd - origSelStart, text.data ());
175 Led_tString ignoredWord = Led_tString{text.
data (), origSelEnd - origSelStart};
176 fIgnoredWords.insert (ignoredWord);
180 virtual void DoChange (
const Led_tString& changeTo)
override
182 size_t origSelStart = fTI.GetSelectionStart ();
183 size_t origSelEnd = fTI.GetSelectionEnd ();
184 TextInteractor::SearchParameters sp;
187 fTI.CopyOut (origSelStart, origSelEnd - origSelStart, text.data ());
188 sp.fMatchString = Led_tString{text.
data (), origSelEnd - origSelStart};
190 fTI.SetSelection (origSelStart, origSelStart);
191 fTI.OnDoReplaceCommand (sp, changeTo);
193 virtual void DoChangeAll (
const Led_tString& changeTo)
override
195 size_t origSelStart = fTI.GetSelectionStart ();
196 size_t origSelEnd = fTI.GetSelectionEnd ();
197 TextInteractor::SearchParameters sp;
200 fTI.CopyOut (origSelStart, origSelEnd - origSelStart, text.data ());
201 sp.fMatchString = Led_tString{text.
data (), origSelEnd - origSelStart};
203 fTI.OnDoReplaceAllCommand (sp, changeTo);
205 virtual bool AddToDictionaryEnabled ()
const override
207 SpellCheckEngine* sce = fTI.GetSpellCheckEngine ();
208 if (sce !=
nullptr) {
209 SpellCheckEngine::UDInterface* udi = sce->GetUDInterface ();
210 if (udi !=
nullptr) {
211 return udi->AddWordToUserDictionarySupported ();
216 virtual void AddToDictionary (
const Led_tString& newWord)
override
218 SpellCheckEngine* sce = fTI.GetSpellCheckEngine ();
219 if (sce !=
nullptr) {
220 SpellCheckEngine::UDInterface* udi = sce->GetUDInterface ();
221 if (udi !=
nullptr) {
222 udi->AddWordToUserDictionary (newWord);
226 fTI.SetSelection (fTI.GetSelectionEnd (), fTI.GetSelectionEnd ());
227 fTI.ScrollToSelection ();
229 virtual void LookupOnWeb (
const Led_tString& word)
override
231 const char kURLBase[] =
"http://dictionary.reference.com/search?q=";
232 Led_URLManager::Get ().Open (kURLBase + Led_tString2ANSIString (word));
234 virtual bool OptionsDialogEnabled ()
const override
239 virtual void OptionsDialog ()
override
246 set<Led_tString> fIgnoredWords;
256void TextInteractor::DialogSupport::DisplayFindDialog (Led_tString* ,
const vector<Led_tString>& ,
257 bool* ,
bool* ,
bool* ,
bool* )
281TextInteractor::DialogSupport::ReplaceButtonPressed
282TextInteractor::DialogSupport::DisplayReplaceDialog (Led_tString* ,
const vector<Led_tString>& ,
283 Led_tString* ,
bool* ,
bool* ,
bool* )
286 return eReplaceButton_Cancel;
289void TextInteractor::DialogSupport::DisplaySpellCheckDialog (SpellCheckDialogCallback& )
299TextInteractor::UndoableContextHelper::UndoableContextHelper (TextInteractor& ti,
const SDKString& cmdName,
bool allowSmartCNPExpansion)
300 : fSimplePlainTextInsertOptimization (false)
301 , fTextInteractor (ti)
303 , fSelStart (ti.GetSelectionStart ())
304 , fSelEnd (ti.GetSelectionEnd ())
306 , fCommandComplete (false)
308 if (allowSmartCNPExpansion) {
309 ti.OptionallyExpandSelectionForSmartCutAndPasteModeDeletes (&fSelStart, &fSelEnd);
311 if (ti.GetCommandHandler () !=
nullptr) {
312 ti.PreInteractiveUndoHelper (&fBefore, fSelStart, fSelEnd, ti.GetSelectionStart (), ti.GetSelectionEnd ());
316TextInteractor::UndoableContextHelper::UndoableContextHelper (TextInteractor& ti,
const SDKString& cmdName,
size_t regionAndSelStart,
317 size_t regionAndSelEnd,
bool allowSmartCNPExpansion)
318 : fSimplePlainTextInsertOptimization (false)
319 , fTextInteractor (ti)
321 , fSelStart (regionAndSelStart)
322 , fSelEnd (regionAndSelEnd)
324 , fCommandComplete (false)
326 if (allowSmartCNPExpansion) {
327 ti.OptionallyExpandSelectionForSmartCutAndPasteModeDeletes (&fSelStart, &fSelEnd);
329 if (ti.GetCommandHandler () !=
nullptr) {
330 ti.PreInteractiveUndoHelper (&fBefore, fSelStart, fSelEnd, regionAndSelStart, regionAndSelEnd);
334TextInteractor::UndoableContextHelper::UndoableContextHelper (TextInteractor& ti,
const SDKString& cmdName,
size_t regionStart,
335 size_t regionEnd,
size_t selStart,
size_t selEnd,
bool allowSmartCNPExpansion)
336 : fSimplePlainTextInsertOptimization (false)
337 , fTextInteractor (ti)
339 , fSelStart (regionStart)
340 , fSelEnd (regionEnd)
342 , fCommandComplete (false)
344 if (allowSmartCNPExpansion) {
345 ti.OptionallyExpandSelectionForSmartCutAndPasteModeDeletes (&fSelStart, &fSelEnd);
347 if (ti.GetCommandHandler () !=
nullptr) {
348 ti.PreInteractiveUndoHelper (&fBefore, fSelStart, fSelEnd, selStart, selEnd);
352TextInteractor::UndoableContextHelper::~UndoableContextHelper ()
354 if (not fCommandComplete) {
373void TextInteractor::UndoableContextHelper::CommandComplete ()
375 fTextInteractor.ScrollToSelection ();
376 if (fTextInteractor.GetCommandHandler () !=
nullptr) {
377 if (GetSimplePlainTextInsertOptimization ()) {
378 fTextInteractor.PostInteractiveSimpleCharInsertUndoHelper (&fBefore, fSelStart, fTextInteractor.GetSelectionEnd (), fCmdName);
381 fTextInteractor.PostInteractiveUndoHelper (&fBefore, fSelStart, fTextInteractor.GetSelectionEnd (), fCmdName);
384 fCommandComplete =
true;
387void TextInteractor::UndoableContextHelper::CommandComplete (
size_t endOfInsert)
389 fTextInteractor.ScrollToSelection ();
390 if (fTextInteractor.GetCommandHandler () !=
nullptr) {
391 if (GetSimplePlainTextInsertOptimization ()) {
392 fTextInteractor.PostInteractiveSimpleCharInsertUndoHelper (&fBefore, fSelStart, endOfInsert, fCmdName);
395 fTextInteractor.PostInteractiveUndoHelper (&fBefore, fSelStart, endOfInsert, fCmdName);
398 fCommandComplete =
true;
406TextInteractor::PreReplaceInfo::PreReplaceInfo ()
407 : fTextInteractor (nullptr)
408 , fUpdateMode (TextInteractor::eNoUpdate)
411 , fWithWhatCharCount (0)
412 , fBoundingUpdateMarker ()
413 , fBoundingUpdateHeight (0)
414 , fStableTypingRegionHeight (0)
418TextInteractor::PreReplaceInfo::~PreReplaceInfo ()
420 if (fTextInteractor !=
nullptr) {
421 fTextInteractor->GetTextStore ().RemoveMarker (&fBoundingUpdateMarker);
422 fTextInteractor =
nullptr;
426TextInteractor::UpdateMode TextInteractor::PreReplaceInfo::GetUpdateMode ()
const
431size_t TextInteractor::PreReplaceInfo::GetFrom ()
const
436size_t TextInteractor::PreReplaceInfo::GetTo ()
const
447TextInteractor::CommandNames TextInteractor::sCommandNames = TextInteractor::MakeDefaultCommandNames ();
448TextInteractor::DialogSupport* TextInteractor::sDialogSupport =
nullptr;
449TextInteractor::SearchParameters TextInteractor::sSearchParameters;
450TextInteractor::ReplaceParameters TextInteractor::sReplaceParameters;
452TextInteractor::TextInteractor ()
453 : fCommandHandler (nullptr)
454 , fSpellCheckEngine (nullptr)
455 , fSuppressCommandBreaksContext (false)
456 , fDefaultUpdateMode (eDelayedUpdate)
457 , fSmartCutAndPasteMode (true)
459 , fLastMouseDownAt (Led_Point (0, 0))
460 , fWholeWindowInvalid (false)
461 , fUseSecondaryHilight (false)
462 , fUseBitmapScrollingOptimization (true)
463 , fSuppressTypedControlCharacters (true)
464 , fInteractiveUpdadeMode (eIndeterminateInteractiveUpdateMode)
465 , fTmpPreReplaceInfo ()
466 , fDoingUpdateModeReplaceOn (nullptr)
467 , fCaretShown (false)
468 , fLeftSideOfSelectionInteresting (false)
469 , fCaretShownAfterPos (true)
474 fScrollBarParamsValid (false)
476 fScrollBarType[h] = eScrollBarNever;
477 fScrollBarType[v] = eScrollBarNever;
480TextInteractor::~TextInteractor ()
482 Assert (fCommandHandler ==
nullptr);
484 Assert (fSpellCheckEngine ==
nullptr);
487TextInteractor::CommandNames TextInteractor::MakeDefaultCommandNames ()
489 TextInteractor::CommandNames cmdNames;
490 cmdNames.fTypingCommandName = Led_SDK_TCHAROF (
"Typing");
491 cmdNames.fCutCommandName = Led_SDK_TCHAROF (
"Cut");
492 cmdNames.fClearCommandName = Led_SDK_TCHAROF (
"Clear");
493 cmdNames.fPasteCommandName = Led_SDK_TCHAROF (
"Paste");
494 cmdNames.fUndoFormatString = Led_SDK_TCHAROF (
"Undo %s");
495 cmdNames.fRedoFormatString = Led_SDK_TCHAROF (
"ReDo %s");
496#if qStroika_Foundation_Common_Platform_Windows
497 cmdNames.fUndoFormatString += Led_SDK_TCHAROF (
"\tCtrl+Z");
498 cmdNames.fRedoFormatString += Led_SDK_TCHAROF (
"\tCtrl+Y");
500 cmdNames.fReplaceCommandName = Led_SDK_TCHAROF (
"Replace");
501 cmdNames.fReplaceAllCommandName = Led_SDK_TCHAROF (
"Replace All");
502 cmdNames.fReplaceAllInSelectionCommandName = Led_SDK_TCHAROF (
"Replace All In Selection");
512bool TextInteractor::OnUpdateCommand (CommandUpdater* enabler)
515 switch (enabler->GetCmdID ()) {
516 case kSelectAll_CmdID: {
517 enabler->SetEnabled (
true);
521 OnUpdateCutCopyClearCommand (enabler);
525 OnUpdateCutCopyClearCommand (enabler);
529 OnUpdatePasteCommand (enabler);
533 OnUpdateCutCopyClearCommand (enabler);
537 OnUpdateUndoRedoCommand (enabler);
541 OnUpdateUndoRedoCommand (enabler);
545 OnUpdateFindCommands (enabler);
548 case kFindAgain_CmdID: {
549 OnUpdateFindCommands (enabler);
552 case kEnterFindString_CmdID: {
553 OnUpdateFindCommands (enabler);
556 case kReplace_CmdID: {
557 OnUpdateFindCommands (enabler);
560 case kReplaceAgain_CmdID: {
561 OnUpdateFindCommands (enabler);
564 case kSpellCheck_CmdID: {
565 OnUpdateSpellCheckCommand (enabler);
568 case kSelectWord_CmdID:
569 case kSelectTextRow_CmdID:
570 case kSelectParagraph_CmdID: {
571 OnUpdateSelectTextCommand (enabler);
584bool TextInteractor::OnPerformCommand (CommandNumber commandNumber)
586 switch (commandNumber) {
587 case kSelectAll_CmdID: {
588 OnSelectAllCommand ();
619 case kFindAgain_CmdID: {
620 OnFindAgainCommand ();
623 case kEnterFindString_CmdID: {
624 OnEnterFindString ();
627 case kReplace_CmdID: {
631 case kReplaceAgain_CmdID: {
632 OnReplaceAgainCommand ();
635 case kSpellCheck_CmdID: {
636 OnSpellCheckCommand ();
639 case kSelectWord_CmdID:
640 case kSelectTextRow_CmdID:
641 case kSelectParagraph_CmdID: {
642 OnPerformSelectTextCommand (commandNumber);
649void TextInteractor::OnUpdateCutCopyClearCommand (CommandUpdater* enabler)
654 static_cast<TextImager*
> (
this)->GetSelection (&start, &end);
655 enabler->SetEnabled (start != end);
658void TextInteractor::OnUpdatePasteCommand (CommandUpdater* enabler)
662 enabler->SetEnabled (
true);
665void TextInteractor::OnUpdateUndoRedoCommand (CommandUpdater* enabler)
668 if (GetCommandHandler () ==
nullptr) {
669 enabler->SetEnabled (
false);
672 if (enabler->GetCmdID () == kUndo_CmdID) {
673 enabler->SetEnabled (GetCommandHandler ()->CanUndo ());
676 Characters::CString::Format (GetCommandNames ().fUndoFormatString.c_str (), GetCommandHandler ()->GetUndoCmdName ());
677 enabler->SetText (menuItemText.c_str ());
679 else if (enabler->GetCmdID () == kRedo_CmdID) {
680 enabler->SetEnabled (GetCommandHandler ()->CanRedo ());
683 Characters::CString::Format (GetCommandNames ().fRedoFormatString.c_str (), GetCommandHandler ()->GetRedoCmdName ());
684 enabler->SetText (menuItemText.c_str ());
689void TextInteractor::OnUpdateSelectTextCommand (CommandUpdater* enabler)
692 enabler->SetEnabled (
true);
695void TextInteractor::OnPerformSelectTextCommand (CommandNumber commandNumber)
698 size_t oldSelStart = GetSelectionStart ();
699 size_t oldSelEnd = GetSelectionEnd ();
700 size_t newSelStart = oldSelStart;
701 size_t newSelEnd = oldSelEnd;
702 switch (commandNumber) {
703 case kSelectWord_CmdID: {
704 size_t wordStart = 0;
706 bool wordReal =
false;
707 GetTextStore ().FindWordBreaks (oldSelStart, &wordStart, &wordEnd, &wordReal);
709 Assert (wordStart <= oldSelStart);
710 newSelStart = wordStart;
714 GetTextStore ().FindWordBreaks (FindPreviousCharacter (oldSelStart), &wordStart, &wordEnd, &wordReal);
716 Assert (wordStart <= oldSelStart);
717 newSelStart = wordStart;
721 GetTextStore ().FindWordBreaks (oldSelEnd, &wordStart, &wordEnd, &wordReal);
726 case kSelectTextRow_CmdID: {
727 newSelStart = GetStartOfRowContainingPosition (oldSelStart);
730 if (oldSelStart == oldSelEnd or oldSelEnd != GetStartOfRowContainingPosition (oldSelEnd)) {
731 newSelEnd = GetEndOfRowContainingPosition (oldSelEnd);
734 case kSelectParagraph_CmdID: {
735 newSelStart = GetTextStore ().GetStartOfLineContainingPosition (oldSelStart);
739 if (oldSelStart == oldSelEnd or oldSelEnd != GetTextStore ().GetStartOfLineContainingPosition (oldSelEnd)) {
740 newSelEnd = GetTextStore ().GetEndOfLineContainingPosition (oldSelEnd);
742 if (newSelEnd < GetEnd ()) {
744 GetTextStore ().CopyOut (newSelEnd, 1, &c);
746 newSelEnd = FindNextCharacter (newSelEnd);
752 SetSelection (newSelStart, newSelEnd);
756 vector<Led_tString> MergeRecentFindStrings (
const Led_tString& s,
const vector<Led_tString>& oldRecents);
759void TextInteractor::OnFindCommand ()
761 SearchParameters parameters = GetSearchParameters ();
762 bool pressedOK =
false;
763 GetDialogSupport ().DisplayFindDialog (¶meters.fMatchString, parameters.fRecentFindStrings, ¶meters.fWrapSearch,
764 ¶meters.fWholeWordSearch, ¶meters.fCaseSensativeSearch, &pressedOK);
765 parameters.fRecentFindStrings = MergeRecentFindStrings (parameters.fMatchString, parameters.fRecentFindStrings);
766 SetSearchParameters (parameters);
768 OnFindAgainCommand ();
772void TextInteractor::OnReplaceCommand ()
774 SearchParameters parameters = GetSearchParameters ();
775 ReplaceParameters rParameters = GetReplaceParameters ();
776 DialogSupport::ReplaceButtonPressed pressed =
777 GetDialogSupport ().DisplayReplaceDialog (¶meters.fMatchString, parameters.fRecentFindStrings, &rParameters.fReplaceWith,
778 ¶meters.fWrapSearch, ¶meters.fWholeWordSearch, ¶meters.fCaseSensativeSearch);
779 parameters.fRecentFindStrings = MergeRecentFindStrings (parameters.fMatchString, parameters.fRecentFindStrings);
780 SetSearchParameters (parameters);
781 SetReplaceParameters (rParameters);
783 case TextInteractor::DialogSupport::eReplaceButton_Find:
784 OnFindAgainCommand ();
786 case TextInteractor::DialogSupport::eReplaceButton_Replace:
787 OnDoReplaceCommand (parameters, rParameters.fReplaceWith);
789 case TextInteractor::DialogSupport::eReplaceButton_ReplaceAll:
790 OnDoReplaceAllCommand (parameters, rParameters.fReplaceWith);
792 case TextInteractor::DialogSupport::eReplaceButton_ReplaceAllInSelection:
793 OnDoReplaceAllInSelectionCommand (parameters, rParameters.fReplaceWith);
798void TextInteractor::OnReplaceAgainCommand ()
800 SearchParameters parameters = GetSearchParameters ();
801 ReplaceParameters rParameters = GetReplaceParameters ();
802 OnDoReplaceCommand (parameters, rParameters.fReplaceWith);
805void TextInteractor::OnDoReplaceCommand (
const SearchParameters& searchFor,
const Led_tString& replaceWith)
807 BreakInGroupedCommands ();
809 size_t origSelStart = GetSelectionStart ();
810 size_t origSelEnd = GetSelectionEnd ();
811 size_t whereTo = GetTextStore ().Find (searchFor, origSelEnd);
812 if ((whereTo == kBadIndex) or (whereTo == origSelStart and whereTo + searchFor.fMatchString.length () == origSelEnd)) {
816 InteractiveModeUpdater iuMode (*
this);
817 size_t replaceStart = whereTo;
818 size_t replaceEnd = whereTo + searchFor.fMatchString.length ();
819 UndoableContextHelper undoContext (*
this, GetCommandNames ().fReplaceCommandName, replaceStart, replaceEnd, GetSelectionStart (),
820 GetSelectionEnd (),
false);
822 InteractiveReplace_ (undoContext.GetUndoRegionStart (), undoContext.GetUndoRegionEnd (), replaceWith.c_str (), replaceWith.length ());
823 SetSelection (whereTo, whereTo + replaceWith.length ());
825 undoContext.CommandComplete ();
826 ScrollToSelection ();
828 BreakInGroupedCommands ();
831void TextInteractor::OnDoReplaceAllCommand (
const SearchParameters& searchFor,
const Led_tString& replaceWith)
833 InteractiveModeUpdater iuMode (*
this);
834 BreakInGroupedCommands ();
837 size_t whereTo = GetTextStore ().Find (searchFor, startAt, GetTextStore ().GetEnd ());
838 if (whereTo == kBadIndex) {
842 size_t replaceStart = whereTo;
843 size_t replaceEnd = whereTo + searchFor.fMatchString.length ();
844 UndoableContextHelper undoContext (*
this, GetCommandNames ().fReplaceAllCommandName, replaceStart, replaceEnd,
845 GetSelectionStart (), GetSelectionEnd (),
false);
847 InteractiveReplace_ (undoContext.GetUndoRegionStart (), undoContext.GetUndoRegionEnd (), replaceWith.c_str (), replaceWith.length ());
848 SetSelection (whereTo, whereTo + replaceWith.length ());
849 startAt = whereTo + replaceWith.length ();
851 undoContext.CommandComplete ();
854 ScrollToSelection ();
855 BreakInGroupedCommands ();
858void TextInteractor::OnDoReplaceAllInSelectionCommand (
const SearchParameters& searchFor,
const Led_tString& replaceWith)
860 InteractiveModeUpdater iuMode (*
this);
861 BreakInGroupedCommands ();
862 size_t startAt = GetSelectionStart ();
863 TempMarker selectionRegion (GetTextStore (), startAt, GetSelectionEnd ());
865 Assert (startAt <= selectionRegion.GetEnd ());
866 size_t whereTo = GetTextStore ().Find (searchFor, startAt, selectionRegion.GetEnd ());
867 if (whereTo == kBadIndex) {
871 size_t replaceStart = whereTo;
872 size_t replaceEnd = whereTo + searchFor.fMatchString.length ();
873 UndoableContextHelper undoContext (*
this, GetCommandNames ().fReplaceAllInSelectionCommandName, replaceStart, replaceEnd,
874 GetSelectionStart (), GetSelectionEnd (),
false);
876 InteractiveReplace_ (undoContext.GetUndoRegionStart (), undoContext.GetUndoRegionEnd (), replaceWith.c_str (), replaceWith.length ());
877 SetSelection (whereTo, whereTo + replaceWith.length ());
878 startAt = whereTo + replaceWith.length ();
880 undoContext.CommandComplete ();
883 ScrollToSelection ();
884 BreakInGroupedCommands ();
887void TextInteractor::OnFindAgainCommand ()
889 TextStore::SearchParameters parameters = GetSearchParameters ();
892 size_t origSelStart = GetSelectionStart ();
893 size_t origSelEnd = GetSelectionEnd ();
894 size_t whereTo = GetTextStore ().Find (parameters, origSelEnd);
895 if ((whereTo == kBadIndex) or (whereTo == origSelStart and whereTo + parameters.fMatchString.length () == origSelEnd)) {
899 SetSelection (whereTo, whereTo + parameters.fMatchString.length ());
900 ScrollToSelection ();
904void TextInteractor::OnEnterFindString ()
906 SearchParameters parameters = GetSearchParameters ();
908 size_t selStart = GetSelectionStart ();
909 size_t selEnd = GetSelectionEnd ();
910 size_t selLength = selEnd - selStart;
913 CopyOut (selStart, selLength, buf.data ());
914 parameters.fMatchString = Led_tString{buf.data (), selLength};
915 parameters.fRecentFindStrings = MergeRecentFindStrings (parameters.fMatchString, parameters.fRecentFindStrings);
916 SetSearchParameters (parameters);
919void TextInteractor::OnUpdateFindCommands (CommandUpdater* enabler)
922 if (enabler->GetCmdID () == kFind_CmdID) {
923 enabler->SetEnabled (
true);
925 else if (enabler->GetCmdID () == kFindAgain_CmdID) {
926 enabler->SetEnabled (GetSearchParameters ().fMatchString.length () != 0);
928 else if (enabler->GetCmdID () == kEnterFindString_CmdID) {
929 enabler->SetEnabled (GetSelectionStart () != GetSelectionEnd ());
931 else if (enabler->GetCmdID () == kReplace_CmdID) {
932 enabler->SetEnabled (
true);
934 else if (enabler->GetCmdID () == kReplaceAgain_CmdID) {
935 enabler->SetEnabled (GetSearchParameters ().fMatchString.length () != 0);
939TextInteractor::SearchParameters TextInteractor::GetSearchParameters ()
const
941 return sSearchParameters;
944void TextInteractor::SetSearchParameters (
const SearchParameters& sp)
946 sSearchParameters = sp;
949TextInteractor::ReplaceParameters TextInteractor::GetReplaceParameters ()
const
951 return sReplaceParameters;
954void TextInteractor::SetReplaceParameters (
const ReplaceParameters& rp)
956 sReplaceParameters = rp;
959vector<Led_tString> TextInteractor::MergeRecentFindStrings (
const Led_tString& s,
const vector<Led_tString>& oldRecents)
961 const unsigned int kMaxEntries = 20;
962 vector<Led_tString> result = oldRecents;
965 vector<Led_tString>::iterator i = std::find (result.begin (), result.end (), s);
966 if (i != result.end ()) {
969 result.insert (result.begin (), s);
970 if (result.size () > kMaxEntries) {
971 result.erase (result.begin () + kMaxEntries, result.end ());
976void TextInteractor::OnSpellCheckCommand ()
978 if (GetSpellCheckEngine () ==
nullptr) {
982 MyCallback cb (*
this);
983 GetDialogSupport ().DisplaySpellCheckDialog (cb);
987void TextInteractor::OnUpdateSpellCheckCommand (CommandUpdater* enabler)
990 enabler->SetEnabled (GetSpellCheckEngine () !=
nullptr);
1001void TextInteractor::SetDefaultUpdateMode (UpdateMode defaultUpdateMode)
1003 if (defaultUpdateMode != eDefaultUpdate) {
1004 fDefaultUpdateMode = defaultUpdateMode;
1019bool TextInteractor::LooksLikeSmartPastableText ([[maybe_unused]]
const Led_tChar* text,
size_t , SmartCNPInfo* smartCNPInfo)
const
1023 if (GetSmartCutAndPasteMode ()) {
1024 size_t selStart = GetSelectionStart ();
1025 size_t selEnd = GetSelectionEnd ();
1028 if (selStart == 0 or selStart >= GetEnd ()) {
1029 smartCNPInfo->fWordBreakAtSelStart =
true;
1032 size_t prev = FindPreviousCharacter (selStart);
1034 CopyOut (prev, 1, &prevC);
1036 CopyOut (selStart, 1, &c);
1037 smartCNPInfo->fWordBreakAtSelStart = (IsShouldBeSepWithWhitespaceWordChar (c) != IsShouldBeSepWithWhitespaceWordChar (prevC));
1040 if (selEnd == 0 or selEnd >= GetEnd ()) {
1041 smartCNPInfo->fWordBreakAtSelEnd =
true;
1044 size_t prev = FindPreviousCharacter (selEnd);
1046 CopyOut (prev, 1, &prevC);
1048 CopyOut (selEnd, 1, &c);
1049 smartCNPInfo->fWordBreakAtSelEnd = (IsShouldBeSepWithWhitespaceWordChar (c) != IsShouldBeSepWithWhitespaceWordChar (prevC));
1069void TextInteractor::OptionallyAddExtraSpaceForSmartCutAndPasteModeAdds (
size_t selStart,
const SmartCNPInfo& smartCNPInfo)
1071 size_t selEnd = GetSelectionEnd ();
1073 Require (0 <= selStart);
1074 Require (selStart <= selEnd);
1075 Require (selEnd <= GetTextStore ().GetEnd ());
1077 if (GetSmartCutAndPasteMode ()) {
1078 if (selEnd > 0 and selEnd < GetTextStore ().GetEnd ()) {
1079 size_t prev = FindPreviousCharacter (selEnd);
1081 CopyOut (prev, 1, &prevC);
1083 CopyOut (selEnd, 1, &c);
1084 if (smartCNPInfo.fWordBreakAtSelEnd and IsShouldBeSepWithWhitespaceWordChar (c) and IsShouldBeSepWithWhitespaceWordChar (prevC)) {
1085 InteractiveReplace_ (selEnd, selEnd, LED_TCHAR_OF (
" "), 1,
false);
1094 SetSelection (selEnd, selEnd);
1098 if (selStart > 0 and selStart < GetTextStore ().GetEnd ()) {
1099 size_t prev = FindPreviousCharacter (selStart);
1101 CopyOut (prev, 1, &prevC);
1103 CopyOut (selStart, 1, &c);
1104 if (smartCNPInfo.fWordBreakAtSelStart and IsShouldBeSepWithWhitespaceWordChar (c) and IsShouldBeSepWithWhitespaceWordChar (prevC)) {
1110 InteractiveReplace_ (selStart, selStart, LED_TCHAR_OF (
" "), 1,
false);
1113 if (IsSmartSpace (c) and IsSmartSpace (prevC)) {
1114 InteractiveReplace_ (selStart, FindNextCharacter (selStart),
nullptr, 0,
false);
1125void TextInteractor::OptionallyExpandSelectionForSmartCutAndPasteModeDeletes (
size_t* selStart,
size_t* selEnd)
1129 Require (0 <= *selStart);
1130 Require (*selStart <= *selEnd);
1131 Require (*selEnd <= GetTextStore ().GetEnd ());
1133 if (GetSmartCutAndPasteMode ()) {
1134 size_t realStart = *selStart;
1135 size_t realEnd = *selEnd;
1136 size_t newStart = realStart;
1137 size_t newEnd = realEnd;
1143 if (realStart < GetEnd ()) {
1145 CopyOut (realStart, 1, &c);
1149 if (realStart > 0) {
1150 CopyOut (FindPreviousCharacter (realStart), 1, &c);
1151 if (IsShouldBeSepWithWhitespaceWordChar (c)) {
1157 if (realStart < realEnd and realEnd < GetEnd ()) {
1159 CopyOut (FindPreviousCharacter (realEnd), 1, &c);
1163 if (realEnd < GetEnd ()) {
1164 CopyOut (realEnd, 1, &c);
1165 if (IsShouldBeSepWithWhitespaceWordChar (c)) {
1177 size_t prev = FindPreviousCharacter (newStart);
1178 CopyOut (prev, 1, &c);
1179 size_t prevprev = FindPreviousCharacter (prev);
1180 Led_tChar prevprevC;
1181 CopyOut (prevprev, 1, &prevprevC);
1182 if (prevprev != prev and IsSmartSpace (c) and not(IsSmartSpace (prevprevC) or prevprevC ==
'\n')) {
1189 if (newEnd < GetEnd ()) {
1190 CopyOut (newEnd, 1, &c);
1191 Led_tChar charBeforeStart =
'\0';
1192 if (newStart != 0) {
1193 CopyOut (FindPreviousCharacter (newStart), 1, &charBeforeStart);
1195 if (IsSmartSpace (c)) {
1196 Assert (newEnd < FindNextCharacter (newEnd));
1197 newEnd = FindNextCharacter (newEnd);
1198 if (newEnd < GetEnd ()) {
1200 Led_tChar nextChar =
'\0';
1201 CopyOut (newEnd, 1, &nextChar);
1202 if (IsShouldBeSepWithWhitespaceWordChar (charBeforeStart) and IsShouldBeSepWithWhitespaceWordChar (nextChar)) {
1203 newEnd = FindPreviousCharacter (newEnd);
1210 *selStart = newStart;
1220void TextInteractor::SetSelectionShown (
bool shown)
1222 SetSelectionShown (shown, eDefaultUpdate);
1225void TextInteractor::SetSelectionShown (
bool shown, UpdateMode updateMode)
1227 if (GetSelectionShown () != shown) {
1228 TextImager::SetSelectionShown (shown);
1229 Refresh (GetSelectionStart (), GetSelectionEnd (), updateMode);
1237void TextInteractor::SetSelection (
size_t start,
size_t end)
1239 Assert (end <= GetEnd ());
1240 UpdateMode updateMode = GetDefaultUpdateMode ();
1243 if (start != GetSelectionStart () or end != GetSelectionEnd ()) {
1244 IdleManager::NonIdleContext nonIdleContext;
1246 size_t oldSelectionStart = GetSelectionStart ();
1247 size_t oldSelectionEnd = GetSelectionEnd ();
1254 if (start == GetSelectionStart ()) {
1255 fLeftSideOfSelectionInteresting =
false;
1257 else if (end == GetSelectionEnd ()) {
1258 fLeftSideOfSelectionInteresting =
true;
1260 else if ((start < GetSelectionStart ()) == (end < GetSelectionEnd ())) {
1261 fLeftSideOfSelectionInteresting = (start < GetSelectionStart ());
1268 InvalidateCaretState ();
1270 TextImager::SetSelection (start, end);
1272 if ((GetSelectionShown () or GetUseSecondaryHilight ()) and updateMode != eNoUpdate) {
1280 UpdateMode useUpdateMode = (updateMode == eImmediateUpdate) ? eDelayedUpdate : updateMode;
1282 size_t lhsOuter = min (oldSelectionStart, GetSelectionStart ());
1283 size_t rhsOuter = max (oldSelectionEnd, GetSelectionEnd ());
1284 size_t lhsInner = max (oldSelectionStart, GetSelectionStart ());
1285 size_t rhsInner = min (oldSelectionEnd, GetSelectionEnd ());
1286 Assert (lhsOuter <= rhsOuter);
1287 Assert (lhsOuter <= lhsInner);
1288 Assert (lhsOuter <= rhsInner);
1289 Assert (lhsOuter <= rhsOuter);
1290 Assert (lhsInner <= rhsOuter);
1291 Assert (rhsInner <= rhsOuter);
1297 Refresh (FindPreviousCharacter (lhsOuter), FindNextCharacter (lhsInner), useUpdateMode);
1298 Refresh (FindPreviousCharacter (rhsInner), FindNextCharacter (rhsOuter), useUpdateMode);
1301 InvalidateCaretState ();
1303 if (updateMode == eImmediateUpdate) {
1306 RecomputeSelectionGoalColumn ();
1309void TextInteractor::SetSelection (
size_t start,
size_t end, UpdateMode updateMode)
1311 TemporarilySetUpdateMode updateModeSetter (*
this, updateMode);
1312 TextImager* tim =
this;
1313 tim->SetSelection (start, end);
1327void TextInteractor::ScrollToSelection (UpdateMode updateMode,
bool forceShowSelectionEndpoint)
1329 size_t selStart = GetSelectionStart ();
1330 size_t selEnd = GetSelectionEnd ();
1340 if (not forceShowSelectionEndpoint and selStart <= GetMarkerPositionOfStartOfWindow () and selEnd >= GetMarkerPositionOfEndOfWindow ()) {
1362 size_t firstCharShown = selStart;
1363 size_t lastCharShown = FindPreviousCharacter (selEnd);
1364 if (fLeftSideOfSelectionInteresting) {
1365 if (firstCharShown != lastCharShown and GetStartOfRowContainingPosition (firstCharShown) != GetStartOfRowContainingPosition (lastCharShown)) {
1366 lastCharShown = firstCharShown;
1368 ScrollSoShowing (firstCharShown, lastCharShown, updateMode);
1371 if (GetCaretShownAfterPos ()) {
1372 lastCharShown = FindNextCharacter (lastCharShown);
1374 if (firstCharShown != lastCharShown and GetStartOfRowContainingPosition (firstCharShown) != GetStartOfRowContainingPosition (lastCharShown)) {
1375 firstCharShown = lastCharShown;
1377 ScrollSoShowing (lastCharShown, firstCharShown, updateMode);
1381void TextInteractor::HookLosingTextStore ()
1383 HookLosingTextStore_ ();
1384 TextImager::HookLosingTextStore ();
1387void TextInteractor::HookLosingTextStore_ ()
1389 AbortReplace (fTmpPreReplaceInfo);
1390 fExternalizer.reset ();
1391 fInternalizer.reset ();
1394void TextInteractor::HookGainedNewTextStore ()
1396 HookGainedNewTextStore_ ();
1397 TextImager::HookGainedNewTextStore ();
1400void TextInteractor::HookGainedNewTextStore_ ()
1402 if (fExternalizer.get () ==
nullptr) {
1403 SetExternalizer (MakeDefaultExternalizer ());
1405 if (fInternalizer.get () ==
nullptr) {
1406 SetInternalizer (MakeDefaultInternalizer ());
1424bool TextInteractor::ProcessSimpleClick (Led_Point clickedAt,
unsigned clickCount,
bool extendSelection,
size_t* dragAnchor)
1427 switch (clickCount) {
1429 size_t newPos = GetCharAtClickLocation (clickedAt);
1430 size_t newSelStart = newPos;
1431 size_t newSelEnd = newPos;
1433 WhileTrackingConstrainSelection (&newSelStart, &newSelEnd);
1434 newPos = newSelStart;
1436 if (extendSelection) {
1437 newSelStart = min (newSelStart, GetSelectionStart ());
1438 newSelEnd = max (newSelEnd, GetSelectionEnd ());
1450 if (extendSelection) {
1452 if (newPos == newSelStart) {
1453 *dragAnchor = newSelEnd;
1456 *dragAnchor = newSelStart;
1460 *dragAnchor = newPos;
1464 if (not extendSelection) {
1465 SetCaretShownAfterPos (GetCharWindowLocation (newPos).top <= clickedAt.v);
1468 WhileTrackingConstrainSelection (&newSelStart, &newSelEnd);
1469 SetSelection (newSelStart, newSelEnd);
1477 DbgTrace (
"TextInteractor::ProcessSimpleClick (tickCount=%f, newMousePos=(%d,%d), clickCount=%d, extendSel=%d, newSelStart=%d, newSelEnd=%d)\n",
1478 Time::GetTickCount (), clickedAt.v, clickedAt.h, clickCount, extendSelection, GetSelectionStart (), GetSelectionEnd ()
1488void TextInteractor::UpdateClickCount (
Time::TimePointSeconds clickAtTime,
const Led_Point& clickAtLocation)
1490 if (ClickTimesAreCloseForDoubleClick (clickAtTime) and PointsAreCloseForDoubleClick (clickAtLocation)) {
1491 IncrementCurClickCount (clickAtTime);
1494 SetCurClickCount (1, clickAtTime);
1496 fLastMouseDownAt = clickAtLocation;
1505 return (fLastClickedAt + Led_GetDoubleClickTime () >= thisClick);
1512bool TextInteractor::PointsAreCloseForDoubleClick (
const Led_Point& p)
1514 const CoordinateType kMultiClickDistance = 4;
1515 CoordinateType hDelta = p.h - fLastMouseDownAt.h;
1519 CoordinateType vDelta = p.v - fLastMouseDownAt.v;
1523 return ((hDelta <= kMultiClickDistance) and (vDelta <= kMultiClickDistance));
1531void TextInteractor::WhileSimpleMouseTracking (Led_Point newMousePos,
size_t dragAnchor)
1533#if qDynamiclyChooseAutoScrollIncrement
1537 bool firstClick = (now - sLastTimeThrough > kClickThreshold);
1539 int increment = firstClick ? 1 : 2;
1541 const int increment = 1;
1544 size_t rhsPos = GetCharAtClickLocation (newMousePos);
1546 size_t ignored = rhsPos;
1547 WhileTrackingConstrainSelection (&rhsPos, &ignored);
1553 if (rhsPos < GetMarkerPositionOfStartOfWindow ()) {
1554 ScrollByIfRoom (-1, eImmediateUpdate);
1555 rhsPos = GetMarkerPositionOfStartOfWindow ();
1557 else if (rhsPos > GetMarkerPositionOfEndOfWindow ()) {
1558 ScrollByIfRoom (1, eImmediateUpdate);
1559 rhsPos = FindNextCharacter (GetMarkerPositionOfEndOfWindow ());
1565 const int kHScrollIncrementFactor = 4;
1566 if (newMousePos.h < GetWindowRect ().left) {
1567 if (GetHScrollPos () > 0) {
1568 SetHScrollPos (max (0,
int (GetHScrollPos ()) - increment * kHScrollIncrementFactor));
1571 else if (newMousePos.h > GetWindowRect ().right) {
1572 SetHScrollPos (min (
static_cast<CoordinateType
> (GetHScrollPos () + increment * kHScrollIncrementFactor),
1573 static_cast<CoordinateType
> (ComputeMaxHScrollPos ())));
1576 size_t newSelStart = min (rhsPos, dragAnchor);
1577 size_t newSelEnd = max (rhsPos, dragAnchor);
1578 WhileTrackingConstrainSelection (&newSelStart, &newSelEnd);
1579 SetSelection (newSelStart, newSelEnd, eImmediateUpdate);
1581#if qDynamiclyChooseAutoScrollIncrement
1582 sLastTimeThrough = now;
1596void TextInteractor::WhileTrackingConstrainSelection (
size_t* selStart,
size_t* selEnd)
1600 Require (GetCurClickCount () > 0);
1601 switch (GetCurClickCount ()) {
1607 WhileTrackingConstrainSelection_ForWholeWords (selStart, selEnd);
1612 WhileTrackingConstrainSelection_ForWholeRows (selStart, selEnd);
1621void TextInteractor::WhileTrackingConstrainSelection_ForWholeWords (
size_t* selStart,
size_t* selEnd)
1626 size_t wordStart = 0;
1628 bool wordReal =
false;
1629 GetTextStore ().FindWordBreaks (*selStart, &wordStart, &wordEnd, &wordReal);
1630 *selStart = wordStart;
1632 GetTextStore ().FindWordBreaks (*selEnd, &wordStart, &wordEnd, &wordReal);
1633#if qDoubleClickSelectsSpaceAfterWord
1636 size_t xWordStart = 0;
1637 size_t xWordEnd = 0;
1638 bool xWordReal =
false;
1639 GetTextStore ().FindWordBreaks (wordEnd, &xWordStart, &xWordEnd, &xWordReal);
1640 if (not xWordReal) {
1652void TextInteractor::WhileTrackingConstrainSelection_ForWholeRows (
size_t* selStart,
size_t* selEnd)
1656 Require (*selStart <= *selEnd);
1658 size_t origSelStart = *selStart;
1659 size_t origSelEnd = *selEnd;
1661 *selStart = GetStartOfRowContainingPosition (origSelStart);
1662 *selEnd = GetStartOfNextRowFromRowContainingPosition (*selEnd);
1664 if (*selEnd <= origSelEnd) {
1665 *selEnd = GetEndOfRowContainingPosition (origSelEnd);
1678size_t TextInteractor::GetCharAtClickLocation (
const Led_Point& where)
const
1680 size_t clickedOnChar = GetCharAtWindowLocation (where);
1681 size_t endOfClickedRow = GetEndOfRowContainingPosition (clickedOnChar);
1694 if (GetEndOfRowContainingPosition (FindPreviousCharacter (clickedOnChar)) == clickedOnChar) {
1695 endOfClickedRow = clickedOnChar;
1698 Assert (GetStartOfRowContainingPosition (clickedOnChar) <= clickedOnChar);
1699 Assert (clickedOnChar <= endOfClickedRow);
1701 if (clickedOnChar < endOfClickedRow) {
1702 Led_Rect charRect = GetCharWindowLocation (clickedOnChar);
1703 bool clickedToLHSOfChar = (where.h <= charRect.left + CoordinateType (charRect.GetWidth ()) / 2 and charRect.GetWidth () != 0);
1704 if (GetTextDirection (clickedOnChar) == eLeftToRight) {
1705 if (not clickedToLHSOfChar) {
1706 clickedOnChar = FindNextCharacter (clickedOnChar);
1710 if (clickedToLHSOfChar) {
1711 clickedOnChar = FindNextCharacter (clickedOnChar);
1715 return (clickedOnChar);
1718void TextInteractor::Draw (
const Led_Rect& ,
bool )
1720 NoteWindowPartiallyUpdated ();
1724void TextInteractor::DrawBefore (
const Led_Rect& ,
bool )
1728 if (not fScrollBarParamsValid) {
1729 UpdateScrollBars ();
1733void TextInteractor::DrawAfter (
const Led_Rect& ,
bool printing)
1735 if (GetUseSecondaryHilight () and not GetSelectionShown () and not printing) {
1737 GetSelectionWindowRegion (&r, GetSelectionStart (), GetSelectionEnd ());
1738 Tablet_Acquirer tablet_ (
this);
1739 Tablet* tablet = tablet_;
1740 tablet->FrameRegion (r, Led_GetSelectedTextBackgroundColor ());
1744void TextInteractor::SetTopRowInWindow (
size_t newTopRow, UpdateMode updateMode)
1746 TemporarilySetUpdateMode updateModeSetter (*
this, updateMode);
1747 TextImager* tim =
this;
1748 tim->SetTopRowInWindow (newTopRow);
1751void TextInteractor::ScrollByIfRoom (ptrdiff_t downBy, UpdateMode updateMode)
1753 TemporarilySetUpdateMode updateModeSetter (*
this, updateMode);
1754 TextImager* tim =
this;
1755 tim->ScrollByIfRoom (downBy);
1758void TextInteractor::ScrollSoShowing (
size_t markerPos,
size_t andTryToShowMarkerPos, UpdateMode updateMode)
1760 TemporarilySetUpdateMode updateModeSetter (*
this, updateMode);
1761 TextImager* tim =
this;
1762 tim->ScrollSoShowing (markerPos, andTryToShowMarkerPos);
1765void TextInteractor::SetDefaultFont (
const IncrementalFontSpecification& defaultFont, UpdateMode updateMode)
1767 TemporarilySetUpdateMode updateModeSetter{*
this, updateMode};
1768 TextImager* tim =
this;
1769 tim->SetDefaultFont (defaultFont);
1773void TextInteractor::SetWindowRect (
const Led_Rect& windowRect, UpdateMode updateMode)
1775 TemporarilySetUpdateMode updateModeSetter (*
this, updateMode);
1776 TextImager* tim =
this;
1777 tim->SetWindowRect (windowRect);
1780void TextInteractor::SetHScrollPos (CoordinateType hScrollPos)
1782 PreScrollInfo preScrollInfo;
1783 PreScrollHelper (eDefaultUpdate, &preScrollInfo);
1784 TextImager::SetHScrollPos (hScrollPos);
1785 PostScrollHelper (preScrollInfo);
1788void TextInteractor::SetHScrollPos (CoordinateType hScrollPos, UpdateMode updateMode)
1790 TemporarilySetUpdateMode updateModeSetter (*
this, updateMode);
1791 TextImager* tim =
this;
1792 tim->SetHScrollPos (hScrollPos);
1795void TextInteractor::PreScrollHelper (UpdateMode updateMode, PreScrollInfo* preScrollInfo)
1797 UpdateMode realUpdateMode = RealUpdateMode (updateMode);
1798 preScrollInfo->fUpdateMode = realUpdateMode;
1799 if (realUpdateMode != eNoUpdate) {
1800 preScrollInfo->fOldWindowStart = GetMarkerPositionOfStartOfWindow ();
1801 preScrollInfo->fOldHScrollPos = GetHScrollPos ();
1802 preScrollInfo->fTryTodoScrollbits = GetUseBitmapScrollingOptimization () and
bool (realUpdateMode == eImmediateUpdate);
1803 if (preScrollInfo->fTryTodoScrollbits) {
1804 preScrollInfo->fOldLastRowStart = GetMarkerPositionOfStartOfLastRowOfWindow ();
1810 preScrollInfo->fTryTodoScrollbits =
false;
1816void TextInteractor::PostScrollHelper (PreScrollInfo preScrollInfo)
1821 size_t newStartOfWindow = GetMarkerPositionOfStartOfWindow ();
1822 preScrollInfo.fUpdateMode = RealUpdateMode (preScrollInfo.fUpdateMode);
1823 if (preScrollInfo.fUpdateMode != eNoUpdate and
1824 ((preScrollInfo.fOldWindowStart != newStartOfWindow) or (preScrollInfo.fOldHScrollPos != GetHScrollPos ()))) {
1827 if (preScrollInfo.fTryTodoScrollbits and preScrollInfo.fOldHScrollPos == GetHScrollPos ()) {
1828 Led_Rect windowRect = GetWindowRect ();
1830 Tablet_Acquirer tablet_{
this};
1831 Tablet* tablet = tablet_;
1832 if (preScrollInfo.fOldWindowStart > newStartOfWindow) {
1838 CoordinateType newPos = GetCharWindowLocation (GetStartOfRowContainingPosition (preScrollInfo.fOldWindowStart)).top;
1841 tablet->ScrollBitsAndInvalRevealed (windowRect, newPos - windowRect.top);
1845 preScrollInfo.fTryTodoScrollbits =
false;
1849 preScrollInfo.fTryTodoScrollbits =
false;
1851 if (preScrollInfo.fTryTodoScrollbits) {
1866 CoordinateType lastRowBottom = GetCharWindowLocation (GetMarkerPositionOfStartOfLastRowOfWindow ()).bottom;
1867 Led_Rect eraser = windowRect;
1868 eraser.top = lastRowBottom;
1869 RefreshWindowRect (eraser, preScrollInfo.fUpdateMode);
1879 CoordinateType newPos = GetCharLocationRowRelativeByPosition (newStartOfWindow, preScrollInfo.fOldWindowStart, 5).top;
1883 tablet->ScrollBitsAndInvalRevealed (windowRect, -newPos);
1887 preScrollInfo.fTryTodoScrollbits =
false;
1891 preScrollInfo.fTryTodoScrollbits =
false;
1894 if (preScrollInfo.fTryTodoScrollbits) {
1898 CoordinateType lastRowBottom = GetCharWindowLocation (preScrollInfo.fOldLastRowStart).bottom;
1899 Led_Rect eraser = windowRect;
1900 eraser.top = lastRowBottom;
1901 RefreshWindowRect (eraser, eDelayedUpdate);
1904 if (preScrollInfo.fUpdateMode == eImmediateUpdate) {
1911 if (preScrollInfo.fTryTodoScrollbits) {
1916 Refresh (preScrollInfo.fUpdateMode);
1920void TextInteractor::Replace (
size_t from,
size_t to,
const Led_tChar* withWhat,
size_t withWhatCharCount, UpdateMode updateMode)
1922 if (from != to or withWhatCharCount != 0) {
1923 Assert (fDoingUpdateModeReplaceOn ==
nullptr);
1924 fDoingUpdateModeReplaceOn =
this;
1926 PreReplaceInfo preReplaceInfo;
1927 PreReplace (from, to, withWhatCharCount, updateMode, &preReplaceInfo);
1928 GetTextStore ().Replace (from, to, withWhat, withWhatCharCount);
1929 PostReplace (preReplaceInfo);
1930 Assert (fDoingUpdateModeReplaceOn ==
this);
1933 Assert (fDoingUpdateModeReplaceOn ==
this);
1934 fDoingUpdateModeReplaceOn =
nullptr;
1937 fDoingUpdateModeReplaceOn =
nullptr;
1941void TextInteractor::AboutToUpdateText (
const MarkerOwner::UpdateInfo& updateInfo)
1943 TextImager::AboutToUpdateText (updateInfo);
1944 if (fDoingUpdateModeReplaceOn !=
this) {
1948 PreReplace (updateInfo.fReplaceFrom, min (updateInfo.fReplaceTo, GetEnd ()), updateInfo.fTextLength, eDefaultUpdate, &fTmpPreReplaceInfo);
1952void TextInteractor::DidUpdateText (
const UpdateInfo& updateInfo)
noexcept
1954 TextImager::DidUpdateText (updateInfo);
1955 if (fDoingUpdateModeReplaceOn !=
this) {
1957 PostReplace (fTmpPreReplaceInfo);
1965void TextInteractor::PreReplace (
size_t from,
size_t to,
size_t withWhatCharCount, UpdateMode updateMode, PreReplaceInfo* preReplaceInfo)
1969 if (preReplaceInfo->fTextInteractor !=
nullptr) {
1970 AbortReplace (*preReplaceInfo);
1973 updateMode = RealUpdateMode (updateMode);
1975 preReplaceInfo->fFrom = from;
1976 preReplaceInfo->fTo = to;
1977 preReplaceInfo->fWithWhatCharCount = withWhatCharCount;
1978 preReplaceInfo->fUpdateMode = updateMode;
1980 if (updateMode == eNoUpdate) {
1984 if (updateMode == eDelayedUpdate and IsWholeWindowInvalid ()) {
1985 preReplaceInfo->fUpdateMode = eNoUpdate;
2004 size_t endOfWindow = GetMarkerPositionOfEndOfWindow ();
2005 if (from > endOfWindow) {
2010 size_t endOfNextRow = GetEndOfRowContainingPosition (FindNextCharacter (endOfWindow));
2011 if (from > endOfNextRow) {
2012 updateMode = eNoUpdate;
2013 preReplaceInfo->fUpdateMode = eNoUpdate;
2019 Assert (updateMode != eNoUpdate);
2031 size_t startPositionOfRowWhereReplaceBegins = GetStartOfRowContainingPosition (from);
2032 size_t startPositionOfRowAfterReplaceEnds = GetEndOfRowContainingPosition (to);
2033 if (startPositionOfRowAfterReplaceEnds < GetTextStore ().GetEnd ()) {
2034 startPositionOfRowAfterReplaceEnds = GetStartOfRowContainingPosition (FindNextCharacter (startPositionOfRowAfterReplaceEnds));
2035 Assert (GetEndOfRowContainingPosition (to) <= startPositionOfRowAfterReplaceEnds);
2037 Assert (startPositionOfRowWhereReplaceBegins <= startPositionOfRowAfterReplaceEnds);
2039 preReplaceInfo->fBoundingUpdateHeight =
2040 GetTextWindowBoundingRect (startPositionOfRowWhereReplaceBegins, startPositionOfRowAfterReplaceEnds).GetHeight ();
2047 size_t expandedFromMarkerPos = 0;
2048 size_t expandedToMarkerPos = 0;
2049 GetStableTypingRegionContaingMarkerRange (from, to, &expandedFromMarkerPos, &expandedToMarkerPos);
2050 if (expandedFromMarkerPos == startPositionOfRowWhereReplaceBegins and expandedToMarkerPos == startPositionOfRowAfterReplaceEnds) {
2052 preReplaceInfo->fStableTypingRegionHeight = preReplaceInfo->fBoundingUpdateHeight;
2053 Assert (preReplaceInfo->fStableTypingRegionHeight == GetTextWindowBoundingRect (expandedFromMarkerPos, expandedToMarkerPos).GetHeight ());
2056 preReplaceInfo->fStableTypingRegionHeight = GetTextWindowBoundingRect (expandedFromMarkerPos, expandedToMarkerPos).GetHeight ();
2064 GetTextStore ().AddMarker (&preReplaceInfo->fBoundingUpdateMarker, startPositionOfRowWhereReplaceBegins,
2065 (startPositionOfRowAfterReplaceEnds - startPositionOfRowWhereReplaceBegins) + 1,
this);
2066 preReplaceInfo->fTextInteractor =
this;
2068 catch (NotFullyInitialized&) {
2070 preReplaceInfo->fUpdateMode = eNoUpdate;
2078void TextInteractor::PostReplace (PreReplaceInfo& preReplaceInfo)
2080 UpdateMode updateMode = preReplaceInfo.fUpdateMode;
2081 if (updateMode != eNoUpdate) {
2082 size_t from = preReplaceInfo.fFrom;
2083 size_t withWhatCharCount = preReplaceInfo.fWithWhatCharCount;
2085 size_t newTo = from + withWhatCharCount;
2088 size_t startPositionOfRowWhereReplaceBegins = preReplaceInfo.fBoundingUpdateMarker.GetStart ();
2089 size_t startPositionOfRowAfterReplaceEnds = preReplaceInfo.fBoundingUpdateMarker.GetEnd () - 1;
2090 Assert (startPositionOfRowWhereReplaceBegins <= startPositionOfRowAfterReplaceEnds);
2092 size_t stableTypingRegionStart = 0;
2093 size_t stableTypingRegionEnd = 0;
2094 GetStableTypingRegionContaingMarkerRange (from, newTo, &stableTypingRegionStart, &stableTypingRegionEnd);
2096 size_t expandedFromMarkerPos = 0;
2097 size_t expandedToMarkerPos = 0;
2098 ExpandedFromAndToInPostReplace (from, newTo, stableTypingRegionStart, stableTypingRegionEnd, startPositionOfRowWhereReplaceBegins,
2099 startPositionOfRowAfterReplaceEnds, &expandedFromMarkerPos, &expandedToMarkerPos);
2101 Led_Rect windowRect = GetWindowRect ();
2102 Led_Rect expandedFromToMarkerRect = GetTextWindowBoundingRect (expandedFromMarkerPos, expandedToMarkerPos);
2103 Led_Rect updateRect = expandedFromToMarkerRect;
2106 updateRect.right = windowRect.right;
2110 Led_Rect revisedRect = expandedFromToMarkerRect;
2111 if (expandedFromMarkerPos != startPositionOfRowWhereReplaceBegins or expandedToMarkerPos != startPositionOfRowAfterReplaceEnds) {
2112 revisedRect = GetTextWindowBoundingRect (startPositionOfRowWhereReplaceBegins, startPositionOfRowAfterReplaceEnds);
2114 Assert (revisedRect == GetTextWindowBoundingRect (startPositionOfRowWhereReplaceBegins, startPositionOfRowAfterReplaceEnds));
2116 if (preReplaceInfo.fBoundingUpdateHeight != revisedRect.GetHeight ()) {
2117 updateRect = Led_Rect (updateRect.top, windowRect.left, windowRect.bottom - updateRect.top, windowRect.GetWidth ());
2123 Led_Rect revisedRect = expandedFromToMarkerRect;
2124 if (expandedFromMarkerPos != stableTypingRegionStart or expandedToMarkerPos != stableTypingRegionEnd) {
2125 revisedRect = GetTextWindowBoundingRect (stableTypingRegionStart, stableTypingRegionEnd);
2127 Assert (revisedRect == GetTextWindowBoundingRect (stableTypingRegionStart, stableTypingRegionEnd));
2128 if (preReplaceInfo.fStableTypingRegionHeight != revisedRect.GetHeight ()) {
2129 updateRect = Led_Rect (updateRect.top, windowRect.left, windowRect.bottom - updateRect.top, windowRect.GetWidth ());
2133 RefreshWindowRect (updateRect, updateMode);
2137void TextInteractor::AbortReplace (PreReplaceInfo& preReplaceInfo)
2139 if (preReplaceInfo.fTextInteractor !=
nullptr) {
2141 preReplaceInfo.fTextInteractor->GetTextStore ().RemoveMarker (&preReplaceInfo.fBoundingUpdateMarker);
2142 preReplaceInfo.fTextInteractor =
nullptr;
2146void TextInteractor::ExpandedFromAndToInPostReplace (
size_t from,
size_t newTo,
size_t stableTypingRegionStart,
2147 size_t stableTypingRegionEnd,
size_t startPositionOfRowWhereReplaceBegins,
2148 size_t startPositionOfRowAfterReplaceEnds,
size_t* expandedFrom,
size_t* expandedTo)
2158 size_t expandedFromMarkerPos = 0;
2159 if (GetStartOfRowContainingPosition (from) == startPositionOfRowWhereReplaceBegins) {
2160 expandedFromMarkerPos = from;
2166 if (expandedFromMarkerPos > startPositionOfRowWhereReplaceBegins) {
2167 expandedFromMarkerPos = FindPreviousCharacter (expandedFromMarkerPos);
2172 expandedFromMarkerPos = stableTypingRegionStart;
2178 size_t expandedToMarkerPos = GetEndOfRowContainingPosition (newTo);
2180 size_t nowStartOfNextRow = expandedToMarkerPos;
2181 if (nowStartOfNextRow < GetTextStore ().GetEnd ()) {
2182 nowStartOfNextRow = GetStartOfRowContainingPosition (FindNextCharacter (nowStartOfNextRow));
2183 Assert (expandedToMarkerPos <= nowStartOfNextRow);
2186 if (nowStartOfNextRow != startPositionOfRowAfterReplaceEnds) {
2188 expandedToMarkerPos = stableTypingRegionEnd;
2192 *expandedFrom = expandedFromMarkerPos;
2193 *expandedTo = expandedToMarkerPos;
2196void TextInteractor::InteractiveReplace (
const Led_tChar* withWhat,
size_t withWhatCharCount, UpdateMode updateMode)
2198 BreakInGroupedCommandsIfDifferentCommand (GetCommandNames ().fTypingCommandName);
2199 InteractiveModeUpdater iuMode{*
this};
2200 UndoableContextHelper undoContext{*
this, GetCommandNames ().fTypingCommandName, withWhatCharCount == 0};
2202 InteractiveReplace_ (undoContext.GetUndoRegionStart (), undoContext.GetUndoRegionEnd (), withWhat, withWhatCharCount,
true,
true, updateMode);
2203 bool anyChanges = InteractiveReplaceEarlyPostReplaceHook (withWhatCharCount);
2204 if (withWhatCharCount == 1 and not anyChanges) {
2206 undoContext.SetSimplePlainTextInsertOptimization (
true);
2209 undoContext.CommandComplete ();
2216void TextInteractor::InteractiveReplace_ (
size_t from,
size_t to,
const Led_tChar* withWhat,
size_t withWhatCharCount,
2217 bool updateCursorPosition,
bool validateTextForCharsetConformance, UpdateMode updateMode)
2220 if (validateTextForCharsetConformance) {
2222 if (not ValidateTextForCharsetConformance (withWhat, withWhatCharCount)) {
2228 TempMarker newSel{GetTextStore (), to + 1, to + 1};
2234 Tablet_Acquirer performanceHackTablet{
this};
2240 SetCaretShownAfterPos (
true);
2242 Replace (from, to, withWhat, withWhatCharCount, updateMode);
2243 if (updateCursorPosition) {
2244 size_t newSelection = newSel.GetStart ();
2245 if (newSelection > 0) {
2249 SetSelection (newSelection, newSelection);
2264bool TextInteractor::InteractiveReplaceEarlyPostReplaceHook (
size_t )
2281void TextInteractor::PreInteractiveUndoHelper (InteractiveReplaceCommand::SavedTextRep** beforeRep,
size_t regionStart,
size_t regionEnd,
2282 size_t selStart,
size_t selEnd)
2284 Require (regionStart <= regionEnd);
2285 Require (selStart <= selEnd);
2287 Require ((*beforeRep) ==
nullptr);
2291 (*beforeRep) = InteractiveUndoHelperMakeTextRep (regionStart, regionEnd, selStart, selEnd);
2300 fCommandHandler->Commit ();
2315void TextInteractor::PostInteractiveUndoHelper (InteractiveReplaceCommand::SavedTextRep** beforeRep,
size_t startOfInsert,
2316 size_t endOfInsert,
const SDKString& cmdName)
2321 SavedTextRep* afterRep =
nullptr;
2323 afterRep = InteractiveUndoHelperMakeTextRep (startOfInsert, endOfInsert, GetSelectionStart (), GetSelectionEnd ());
2324 PostInteractiveUndoPostHelper (beforeRep, &afterRep, startOfInsert, cmdName);
2327 delete (*beforeRep);
2328 (*beforeRep) =
nullptr;
2340void TextInteractor::PostInteractiveSimpleCharInsertUndoHelper (InteractiveReplaceCommand::SavedTextRep** beforeRep,
size_t startOfInsert,
2341 size_t endOfInsert,
const SDKString& cmdName)
2346 if (endOfInsert - startOfInsert == 1) {
2348 CopyOut (startOfInsert, 1, &c);
2349 if (fCommandHandler->PostUpdateSimpleTextInsert (startOfInsert, c)) {
2351 *beforeRep =
nullptr;
2355 SavedTextRep* afterRep =
new InteractiveReplaceCommand::PlainTextRep (GetSelectionStart (), GetSelectionEnd (), &c, 1);
2356 PostInteractiveUndoPostHelper (beforeRep, &afterRep, startOfInsert, cmdName);
2357 Assert (afterRep ==
nullptr);
2361 PostInteractiveUndoHelper (beforeRep, startOfInsert, endOfInsert, cmdName);
2372void TextInteractor::PostInteractiveUndoPostHelper (InteractiveReplaceCommand::SavedTextRep** beforeRep,
2373 InteractiveReplaceCommand::SavedTextRep** afterRep,
size_t startOfInsert,
const SDKString& cmdName)
2379 if (*beforeRep !=
nullptr and *afterRep !=
nullptr) {
2382 InteractiveReplaceCommand* cmd =
new InteractiveReplaceCommand (*beforeRep, *afterRep, startOfInsert, cmdName);
2383 *beforeRep =
nullptr;
2384 *afterRep =
nullptr;
2385 fCommandHandler->Post (cmd);
2390 *beforeRep =
nullptr;
2392 *afterRep =
nullptr;
2397InteractiveReplaceCommand::SavedTextRep* TextInteractor::InteractiveUndoHelperMakeTextRep (
size_t regionStart,
size_t regionEnd,
2398 size_t selStart,
size_t selEnd)
2400 if (regionStart == regionEnd) {
2402 return new InteractiveReplaceCommand::PlainTextRep (selStart, selEnd,
nullptr, 0);
2405 return new FlavorSavorTextRep (
this, regionStart, regionEnd, selStart, selEnd);
2409void TextInteractor::OnUndoCommand ()
2411 InteractiveModeUpdater iuMode (*
this);
2412 if (GetCommandHandler () !=
nullptr and GetCommandHandler ()->CanUndo ()) {
2413 GetCommandHandler ()->DoUndo (*
this);
2414 ScrollToSelection ();
2421void TextInteractor::OnRedoCommand ()
2423 InteractiveModeUpdater iuMode (*
this);
2424 if (GetCommandHandler () !=
nullptr and GetCommandHandler ()->CanRedo ()) {
2425 GetCommandHandler ()->DoRedo (*
this);
2426 ScrollToSelection ();
2433void TextInteractor::Refresh (
size_t from,
size_t to, UpdateMode updateMode)
const
2435 Require (from <= to);
2436 updateMode = RealUpdateMode (updateMode);
2437 if ((updateMode != eNoUpdate) and (from != to)) {
2438 if (updateMode == eDelayedUpdate and IsWholeWindowInvalid ()) {
2446 Led_Rect refreshRect = GetTextWindowBoundingRect (from, to);
2447 RefreshWindowRect_ (refreshRect, updateMode);
2451void TextInteractor::Refresh (
const Marker* range, UpdateMode updateMode)
const
2454 updateMode = RealUpdateMode (updateMode);
2455 if (updateMode != eNoUpdate) {
2456 if (updateMode == eDelayedUpdate and IsWholeWindowInvalid ()) {
2459 Refresh (range->GetStart (), range->GetEnd (), updateMode);
2468void TextInteractor::DoSingleCharCursorEdit (CursorMovementDirection direction, CursorMovementUnit movementUnit,
2469 CursorMovementAction action, UpdateMode updateMode,
bool scrollToSelection)
2471 IdleManager::NonIdleContext nonIdleContext;
2473 size_t oldStartSel = GetSelectionStart ();
2474 size_t oldEndSel = GetSelectionEnd ();
2475 Assert (GetSelectionEnd () <= GetLength () + 1);
2477 size_t newStartSel = oldStartSel;
2478 size_t newEndSel = oldEndSel;
2480 UpdateMode useUpdateMode = (updateMode == eImmediateUpdate) ? eDelayedUpdate : updateMode;
2482 GoalColumnRecomputerControlContext skipRecompute (*
this, action == eCursorMoving and movementUnit == eCursorByRow and
2483 (direction == eCursorBack or direction == eCursorForward));
2494 if (movementUnit == eCursorByRow and GetStartOfRowContainingPosition (newStartSel) == newStartSel) {
2495 if (GetCaretShownAfterPos ()) {
2496 if (direction == eCursorToEnd and GetEndOfRowContainingPosition (newStartSel) == newStartSel) {
2497 goto SkipNavigation;
2501 if (direction == eCursorToStart) {
2504 newStartSel = FindPreviousCharacter (newStartSel);
2506 if (direction == eCursorToEnd) {
2507 goto SkipNavigation;
2515 if (movementUnit == eCursorByChar) {
2516 SetCaretShownAfterPos (
true);
2518 if (movementUnit == eCursorByRow) {
2519 switch (direction) {
2520 case eCursorToStart:
2521 SetCaretShownAfterPos (
true);
2524 SetCaretShownAfterPos (
false);
2529 if (action != eCursorExtendingSelection or (oldStartSel == oldEndSel)) {
2530 fLeftSideOfSelectionInteresting = (direction == eCursorBack or direction == eCursorToStart);
2532 if (fLeftSideOfSelectionInteresting) {
2533 newStartSel = ComputeRelativePosition (newStartSel, direction, movementUnit);
2534 if (action == eCursorMoving) {
2535 newEndSel = newStartSel;
2539 newEndSel = ComputeRelativePosition (newEndSel, direction, movementUnit);
2540 if (action == eCursorMoving) {
2541 newStartSel = newEndSel;
2548 if (newEndSel < newStartSel) {
2549 size_t tmp = newStartSel;
2550 newStartSel = newEndSel;
2553 Assert (newStartSel <= newEndSel);
2559 case eCursorDestroying: {
2560 if (oldStartSel == oldEndSel) {
2565 Assert (newEndSel >= newStartSel);
2566 size_t howMany = newEndSel - newStartSel;
2568 bool oldCutAndPaste = GetSmartCutAndPasteMode ();
2570 SetSmartCutAndPasteMode (
false);
2572 BreakInGroupedCommandsIfDifferentCommand (GetCommandNames ().fClearCommandName);
2573 InteractiveModeUpdater iuMode (*
this);
2574 UndoableContextHelper undoContext (*
this, GetCommandNames ().fClearCommandName, newStartSel, newEndSel,
2575 GetSelectionStart (), GetSelectionEnd (),
true);
2577 InteractiveReplace_ (undoContext.GetUndoRegionStart (), undoContext.GetUndoRegionEnd (), LED_TCHAR_OF (
""),
2578 0,
true,
true, useUpdateMode);
2580 undoContext.CommandComplete ();
2585 GetSelection (&newStartSel, &newEndSel);
2586 SetSmartCutAndPasteMode (oldCutAndPaste);
2589 SetSmartCutAndPasteMode (oldCutAndPaste);
2601 Assert (oldEndSel >= oldStartSel);
2602 Assert (oldStartSel == GetSelectionStart ());
2603 Assert (oldEndSel == GetSelectionEnd ());
2608 GetSelection (&newStartSel, &newEndSel);
2612 case eCursorMoving: {
2616 case eCursorExtendingSelection: {
2630 SetSelection (newStartSel, newEndSel, useUpdateMode);
2632 if (scrollToSelection) {
2633 ScrollToSelection (useUpdateMode,
true);
2636 if (updateMode == eImmediateUpdate) {
2641void TextInteractor::OnCutCommand ()
2643 InteractiveModeUpdater iuMode (*
this);
2644 BreakInGroupedCommands ();
2645 if (GetSelectionStart () != GetSelectionEnd ()) {
2647 UndoableContextHelper undoContext (*
this, GetCommandNames ().fCutCommandName,
true);
2649 InteractiveReplace_ (undoContext.GetUndoRegionStart (), undoContext.GetUndoRegionEnd (), LED_TCHAR_OF (
""), 0);
2651 undoContext.CommandComplete ();
2653 BreakInGroupedCommands ();
2656void TextInteractor::OnCopyCommand ()
2658 size_t start = GetSelectionStart ();
2659 size_t end = GetSelectionEnd ();
2660 Assert (start <= end);
2662 BreakInGroupedCommands ();
2664 if (OnCopyCommand_Before ()) {
2666 OnCopyCommand_CopyFlavors ();
2669 OnCopyCommand_After ();
2672 OnCopyCommand_After ();
2677void TextInteractor::OnPasteCommand ()
2679 InteractiveModeUpdater iuMode (*
this);
2680 BreakInGroupedCommands ();
2682 if (OnPasteCommand_Before ()) {
2684 UndoableContextHelper undoContext (*
this, GetCommandNames ().fPasteCommandName,
false);
2686 OnPasteCommand_PasteBestFlavor ();
2688 undoContext.CommandComplete ();
2691 OnPasteCommand_After ();
2694 OnPasteCommand_After ();
2696 BreakInGroupedCommands ();
2699void TextInteractor::OnClearCommand ()
2701 InteractiveModeUpdater iuMode (*
this);
2702 BreakInGroupedCommands ();
2703 UndoableContextHelper undoContext (*
this, GetCommandNames ().fClearCommandName,
true);
2705 InteractiveReplace_ (undoContext.GetUndoRegionStart (), undoContext.GetUndoRegionEnd (), LED_TCHAR_OF (
""), 0);
2707 undoContext.CommandComplete ();
2708 BreakInGroupedCommands ();
2724bool TextInteractor::OnCopyCommand_Before ()
2734void TextInteractor::OnCopyCommand_After ()
2743void TextInteractor::OnCopyCommand_CopyFlavors ()
2745 WriterClipboardFlavorPackage writer;
2746 ExternalizeFlavors (writer);
2749bool TextInteractor::ShouldEnablePasteCommand ()
const
2751 return Led_ClipboardObjectAcquire::FormatAvailable_TEXT ();
2766bool TextInteractor::OnPasteCommand_Before ()
2776void TextInteractor::OnPasteCommand_After ()
2785void TextInteractor::OnPasteCommand_PasteBestFlavor ()
2787#if qStroika_Foundation_Common_Platform_Windows && 0
2791 long clipFormat = 0;
2792 while ((clipFormat = ::EnumClipboardFormats (clipFormat)) != 0) {
2794 int nChars = ::GetClipboardFormatName (clipFormat, buf, std::size (buf));
2799 ReaderClipboardFlavorPackage clipData;
2801 SmartCNPInfo smartCNPInfo;
2802 bool doSmartCNP = PasteLooksLikeSmartCNP (&smartCNPInfo);
2803 size_t savedSelStart = GetSelectionStart ();
2804 InternalizeBestFlavor (clipData);
2805 Assert (savedSelStart <= GetSelectionStart ());
2807 OptionallyAddExtraSpaceForSmartCutAndPasteModeAdds (savedSelStart, smartCNPInfo);
2816void TextInteractor::OnPasteCommand_PasteFlavor_Specific (Led_ClipFormat format)
2818 ReaderClipboardFlavorPackage clipData;
2819 SmartCNPInfo smartCNPInfo;
2820 bool doSmartCNP = PasteLooksLikeSmartCNP (&smartCNPInfo);
2821 size_t savedSelStart = GetSelectionStart ();
2822 InternalizeFlavor_Specific (clipData, format);
2823 Assert (savedSelStart <= GetSelectionStart ());
2825 OptionallyAddExtraSpaceForSmartCutAndPasteModeAdds (savedSelStart, smartCNPInfo);
2834bool TextInteractor::PasteLooksLikeSmartCNP (SmartCNPInfo* scnpInfo)
const
2837 ReaderClipboardFlavorPackage clipData;
2838 bool doSmartCNP = GetSmartCutAndPasteMode () and clipData.GetFlavorAvailable_TEXT ();
2843 size_t length = clipData.GetFlavorSize (kTEXTClipFormat);
2844 Led_ClipFormat textFormat = kTEXTClipFormat;
2847 length = clipData.ReadFlavorData (textFormat, length, buf.data ());
2849 Led_tChar* buffp =
reinterpret_cast<Led_tChar*
> (
static_cast<char*
> (buf));
2850 size_t nTChars = length /
sizeof (Led_tChar);
2851 doSmartCNP = LooksLikeSmartPastableText (buffp, nTChars, scnpInfo);
2862void TextInteractor::OnSelectAllCommand ()
2864 SetSelection (0, GetLength ());
2867bool TextInteractor::CanAcceptFlavor (Led_ClipFormat clipFormat)
const
2869 return (kTEXTClipFormat == clipFormat or kFILEClipFormat == clipFormat);
2872void TextInteractor::InternalizeBestFlavor (
ReaderFlavorPackage& flavorPackage,
bool updateCursorPosition,
bool autoScroll, UpdateMode updateMode)
2874 size_t start = GetSelectionStart ();
2875 size_t end = GetSelectionEnd ();
2879 TempMarker newSel{GetTextStore (), end + 1, end + 1};
2884 good = fInternalizer->InternalizeBestFlavor (flavorPackage, start, end);
2885 if (good and updateCursorPosition) {
2886 SetCaretShownAfterPos (
true);
2891 size_t newSelection = newSel.GetStart ();
2892 if (newSelection > start) {
2896 SetSelection (newSelection, newSelection);
2902 ScrollToSelection ();
2904 if (updateMode == eImmediateUpdate) {
2917void TextInteractor::InternalizeFlavor_Specific (
ReaderFlavorPackage& flavorPackage, Led_ClipFormat format,
bool updateCursorPosition,
2918 bool autoScroll, UpdateMode updateMode)
2920 size_t start = GetSelectionStart ();
2921 size_t end = GetSelectionEnd ();
2925 TempMarker newSel{GetTextStore (), end + 1, end + 1};
2931 if (format == kTEXTClipFormat) {
2932 good = fInternalizer->InternalizeFlavor_TEXT (flavorPackage, start, end);
2934 else if (format == kFILEClipFormat) {
2935 good = fInternalizer->InternalizeFlavor_FILE (flavorPackage, start, end);
2938 good = fInternalizer->InternalizeBestFlavor (flavorPackage, start, end);
2941 if (good and updateCursorPosition) {
2942 SetCaretShownAfterPos (
true);
2947 size_t newSelection = newSel.GetStart ();
2948 if (newSelection > start) {
2952 SetSelection (newSelection, newSelection);
2958 ScrollToSelection ();
2960 if (updateMode == eImmediateUpdate) {
2975shared_ptr<FlavorPackageInternalizer> TextInteractor::MakeDefaultInternalizer ()
2977 return Memory::MakeSharedPtr<FlavorPackageInternalizer> (GetTextStore ());
2984void TextInteractor::HookInternalizerChanged ()
2995 fExternalizer->ExternalizeFlavors (flavorPackage, GetSelectionStart (), GetSelectionEnd ());
3005 fExternalizer->ExternalizeBestFlavor (flavorPackage, GetSelectionStart (), GetSelectionEnd ());
3014shared_ptr<FlavorPackageExternalizer> TextInteractor::MakeDefaultExternalizer ()
3016 return Memory::MakeSharedPtr<FlavorPackageExternalizer> (GetTextStore ());
3023void TextInteractor::HookExternalizerChanged ()
3033void TextInteractor::OnBadUserInput ()
3037 throw BadUserInput{};
3059void TextInteractor::SetScrollBarType (VHSelect vh, ScrollBarType scrollBarType)
3061 if (GetScrollBarType (vh) != scrollBarType) {
3062 InvalidateScrollBarParameters ();
3063 SetScrollBarType_ (vh, scrollBarType);
3072void TextInteractor::InvalidateScrollBarParameters ()
3074 InvalidateScrollBarParameters_ ();
3084void TextInteractor::UpdateScrollBars ()
3086 UpdateScrollBars_ ();
3093void TextInteractor::SetCaretShown (
bool shown)
3095 if (GetCaretShown () != shown) {
3096 fCaretShown = shown;
3097 InvalidateCaretState ();
3098#if qStroika_Foundation_Common_Platform_MacOS
3102 RefreshWindowRect (CalculateCaretRect ());
3116bool TextInteractor::GetCaretShownSituation ()
const
3118 size_t selStart = 0;
3120 GetSelection (&selStart, &selEnd);
3121 return selStart == selEnd;
3128void TextInteractor::SetCaretShownAfterPos (
bool shownAfterPos)
3130 if (GetCaretShownAfterPos () != shownAfterPos) {
3131 InvalidateCaretState ();
3132 fCaretShownAfterPos = shownAfterPos;
3133 InvalidateCaretState ();
3153Led_Rect TextInteractor::CalculateCaretRect ()
const
3155 size_t selEnd = GetSelectionEnd ();
3156 if (GetSelectionStart () == selEnd) {
3157 bool showAfter = GetCaretShownAfterPos ();
3162 size_t charAfterPos = showAfter ? selEnd : FindPreviousCharacter (selEnd);
3163 TextDirection textDirection = GetTextDirection (charAfterPos);
3164 Led_Rect caretRect = GetCharWindowLocation (charAfterPos);
3166 if (caretRect.GetBottom () < GetWindowRect ().GetTop () or caretRect.GetTop () > GetWindowRect ().GetBottom ()) {
3167 return Led_Rect{0, 0, 0, 0};
3170 Led_Rect origCaretRect = caretRect;
3171 FontMetrics fontMetrics = GetFontMetricsAt (charAfterPos);
3174 DistanceType baseLineFromTop = GetRowRelativeBaselineOfRowContainingPosition (charAfterPos);
3175 CoordinateType realBaseLine = baseLineFromTop + caretRect.top;
3178 caretRect.top = realBaseLine - fontMetrics.GetAscent ();
3179 caretRect.bottom = realBaseLine + fontMetrics.GetDescent ();
3184 if (caretRect.top < origCaretRect.top) {
3185 DistanceType diff = origCaretRect.GetTop () - caretRect.GetTop ();
3186 caretRect += Led_Point (diff, 0);
3190 caretRect.SetTop (max (caretRect.GetTop (), origCaretRect.GetTop ()));
3191 caretRect.bottom = min (caretRect.GetBottom (), origCaretRect.GetBottom ());
3193 if (textDirection == eLeftToRight) {
3194 if (not showAfter) {
3195 caretRect.left = caretRect.right;
3199 caretRect.left = caretRect.right;
3202 const CoordinateType kCaretWidth = 1;
3204 const CoordinateType kSluff = kCaretWidth + 1;
3205 if (caretRect.GetLeft () + kSluff > GetWindowRect ().GetRight ()) {
3206 caretRect.SetLeft (GetWindowRect ().GetRight () - kSluff);
3208 caretRect.SetRight (caretRect.GetLeft () + kCaretWidth);
3210 Ensure (not caretRect.IsEmpty ());
3214 return (Led_Rect{0, 0, 0, 0});
3218void TextInteractor::InvalidateCaretState ()
3220 if (IsWholeWindowInvalid ()) {
3223 if (GetCaretShown () and (GetSelectionStart () == GetSelectionEnd ())) {
3224 RefreshWindowRect (CalculateCaretRect ());
3236void TextInteractor::OnTypedNormalCharacter (Led_tChar theChar,
bool ,
bool ,
bool ,
3237 bool controlPressed,
bool )
3239 IdleManager::NonIdleContext nonIdleContext;
3241 Assert (GetSelectionEnd () <= GetLength () + 1);
3243 if (GetSuppressTypedControlCharacters ()) {
3245 if (controlChar && (theChar ==
'\r' || theChar ==
'\n' || theChar ==
' ' || theChar ==
'\t' || theChar ==
'\b')) {
3246 controlChar =
false;
3256 CursorMovementDirection dir = eCursorBack;
3257 CursorMovementUnit unit = controlPressed ? eCursorByWord : eCursorByChar;
3258 CursorMovementAction action = eCursorDestroying;
3259 DoSingleCharCursorEdit (dir, unit, action, eDefaultUpdate);
3263 if (theChar ==
'\n') {
3264 BreakInGroupedCommands ();
3266 InteractiveReplace (&theChar, 1, eDefaultUpdate);
3270 ScrollToSelection ();
3271#if qPeekForMoreCharsOnUserTyping
3272 UpdateIfNoKeysPending ();
3278#if qStroika_Foundation_Common_Platform_MacOS || qStroika_FeatureSupported_XWindows
3279float TextInteractor::GetTickCountBetweenBlinks ()
3281#if qStroika_Foundation_Common_Platform_MacOS
3282 return ::GetCaretTime () / 60.0;
3283#elif qStroika_FeatureSupported_XWindows
3289bool TextInteractor::DelaySomeForScrollBarClick ()
3293 const int kTimesForFirstClick = 2;
3295 static short sTimesThruBeforeReset;
3299 fLastScrolledAt = now + kDelayAfterFirstTicks;
3300 sTimesThruBeforeReset = 1;
3303 else if (fLastScrolledAt < now) {
3304 ++sTimesThruBeforeReset;
3305 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