Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
TextInteractor.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Frameworks_Led_TextInteractor_h_
5#define _Stroika_Frameworks_Led_TextInteractor_h_ 1
6
7#include "Stroika/Frameworks/StroikaPreComp.h"
8
10
11/*
12@MODULE: TextInteractor
13@DESCRIPTION:
14 <p>This module defines the @'TextInteractor' class, which subclasses from @'TextImager'
15 and introduces user-interaction
16 behavior - such as keyclicks, mouse tracking, and the notion of @'TextInteractor::UpdateMode' s.</p>
17 */
18
19#include "Stroika/Frameworks/Led/Command.h"
20#include "Stroika/Frameworks/Led/FlavorPackage.h"
21#include "Stroika/Frameworks/Led/SpellCheckEngine.h"
22#include "Stroika/Frameworks/Led/TextImager.h"
23
24namespace Stroika::Frameworks::Led {
25
27
28// Private Led Macro utility to define command numbers (cannot use Math::RoundUpTo use used to init enums - at least on msvc2k17)
29#define RoundUpToNearest_CMDNUMs_MACRO(x, n) (((x + 1) & ~(n - 1)) + n)
30
31#if qStroika_Frameworks_Led_SupportGDI
32 /*
33 @CLASS: TextInteractor
34 @BASES: virtual @'TextImager'
35 @DESCRIPTION: <p>TextInteractors are special @'TextImager's which respond to events
36 (such as keyclicks), handle mouse tracking,
37 and are designed to work with some sort of windowing system. They have a
38 concept of Update events, and having their content data out of sync with
39 that which is displayed in the window (inval/validate region). They also
40 provide support for things like a selection, and cursoring through the
41 selection, and word selection, etc.</p>
42
43 <p>Note that TextInteractors are still abstract classes, and know nothing
44 about particular windowing systems, or class libraries. They do what can
45 be done genericly, without having yet made a choice about these things.
46 TextInteractor mainly serves to collect common code/functionality which
47 can be shared accross (for example) MFC/OpenDoc/TCL/PowerPlant/PowerPlant, etc.
48 See @'Led_PPView', @'Led_MacOS_Helper<BASE_INTERACTOR>', @'Led_MFC', @'Led_Win32_Helper<BASE_INTERACTOR>'
49 @'Led_Gtk_Helper<BASE_INTERACTOR,GTKBASEINFO>', etc for more information on class-library-specific
50 integration.</p>
51 */
52 class TextInteractor : public virtual TextImager {
53 protected:
54 TextInteractor ();
55
56 public:
57 virtual ~TextInteractor ();
58
59 /*
60 * By default we have none. If you set one, it will be notified/used for undo
61 * support. It is callers responsability to free the command handler, and must be
62 * done BEFORE we are destroyed, and we must be notified (via SetCommandHandler(nullptr))
63 * BEFORE CommandHandler is destroyed.
64 */
65 public:
66 nonvirtual CommandHandler* GetCommandHandler () const;
67 virtual void SetCommandHandler (CommandHandler* commandHandler);
68
69 private:
70 CommandHandler* fCommandHandler;
71
72 public:
73 nonvirtual void BreakInGroupedCommands ();
74 nonvirtual void BreakInGroupedCommandsIfDifferentCommand (const SDKString& cmdName);
75
76 public:
77 class SuppressCommandBreaksContext;
78
79 private:
80 bool fSuppressCommandBreaksContext;
81
82 public:
83 struct CommandNames;
84
85 // This class builds commands with command names. The UI may wish to change these
86 // names (eg. to customize for particular languages, etc)
87 // Just patch these strings here, and commands will be created with these names.
88 // (These names appear in text of undo menu item)
89 public:
90 static const CommandNames& GetCommandNames ();
91 static void SetCommandNames (const CommandNames& cmdNames);
92 static CommandNames MakeDefaultCommandNames ();
93
94 private:
95 static CommandNames sCommandNames;
96
97 public:
98 using CommandNumber = int;
99
100 public:
101 static const CommandNumber kNoCommand_CmdID = 0;
102
103 public:
104 enum {
105 kTextInteractorCommand_First = 0x100,
106
107 kUndo_CmdID = kTextInteractorCommand_First,
108 kRedo_CmdID,
109 kSelectAll_CmdID,
110 kCut_CmdID,
111 kCopy_CmdID,
112 kPaste_CmdID,
113 kClear_CmdID,
114
115 kSelectWord_CmdID,
116 kSelectTextRow_CmdID,
117 kSelectParagraph_CmdID,
118
119 kFind_CmdID,
120 kFindAgain_CmdID,
121 kEnterFindString_CmdID,
122 kReplace_CmdID,
123 kReplaceAgain_CmdID,
124
125 kSpellCheck_CmdID,
126
127 kTextInteractorCommand_Last = kTextInteractorCommand_First + 0xff
128 };
129
130 public:
131 class CommandUpdater;
132
133 public:
134 class DialogSupport;
135 static DialogSupport& GetDialogSupport ();
136 static void SetDialogSupport (DialogSupport* ds);
137
138 private:
139 static DialogSupport* sDialogSupport;
140
141 public:
142 virtual bool OnUpdateCommand (CommandUpdater* enabler);
143 virtual bool OnPerformCommand (CommandNumber commandNumber);
144
145 public:
146 virtual void OnUpdateCutCopyClearCommand (CommandUpdater* enabler);
147 virtual void OnUpdatePasteCommand (CommandUpdater* enabler);
148 virtual void OnUpdateUndoRedoCommand (CommandUpdater* enabler);
149
150 public:
151 virtual void OnUpdateSelectTextCommand (CommandUpdater* enabler);
152 virtual void OnPerformSelectTextCommand (CommandNumber commandNumber);
153
154 // Find related commands
155 public:
156 class SearchParameters;
157 class ReplaceParameters;
158
159 public:
160 virtual void OnFindCommand ();
161 virtual void OnFindAgainCommand ();
162 virtual void OnEnterFindString ();
163 virtual void OnReplaceCommand ();
164 virtual void OnReplaceAgainCommand ();
165 virtual void OnDoReplaceCommand (const SearchParameters& searchFor, const Led_tString& replaceWith);
166 virtual void OnDoReplaceAllCommand (const SearchParameters& searchFor, const Led_tString& replaceWith);
167 virtual void OnDoReplaceAllInSelectionCommand (const SearchParameters& searchFor, const Led_tString& replaceWith);
168 virtual void OnUpdateFindCommands (CommandUpdater* enabler);
169
170 private:
171 static SearchParameters sSearchParameters;
172
173 public:
174 virtual SearchParameters GetSearchParameters () const;
175 virtual void SetSearchParameters (const SearchParameters& sp);
176
177 private:
178 static ReplaceParameters sReplaceParameters;
179
180 public:
181 virtual ReplaceParameters GetReplaceParameters () const;
182 virtual void SetReplaceParameters (const ReplaceParameters& rp);
183
184 protected:
185 virtual vector<Led_tString> MergeRecentFindStrings (const Led_tString& s, const vector<Led_tString>& oldRecents);
186
187 public:
188 virtual void OnSpellCheckCommand ();
189 virtual void OnUpdateSpellCheckCommand (CommandUpdater* enabler);
190
191 public:
192 nonvirtual SpellCheckEngine* GetSpellCheckEngine () const;
193 nonvirtual void SetSpellCheckEngine (SpellCheckEngine* spellCheckEngine);
194
195 private:
196 SpellCheckEngine* fSpellCheckEngine;
197
198 protected:
199 class UndoableContextHelper;
200
201 friend class UndoableContextHelper;
202
203 public:
204 /*
205 @CLASS: TextInteractor::UpdateMode
206 @DESCRIPTION: <p>Support for controlling how/when the window is updated. This is a key difference between
207 a @'TextImager' and a @'TextInteractor'. A @'TextInteractor' introduces the concept of a real GUI
208 window that can get out of data, and needs to be updated. These updateModes control
209 the basic updating/timing strategies for redrawing portions of the textimager.</p>
210 */
211 enum UpdateMode {
212 eDelayedUpdate,
213 eImmediateUpdate,
214 eNoUpdate,
215 eDefaultUpdate
216 };
217
218 /*
219 #if 0
220 * Sometimes its convenient to globally (perhaps modally is a better word) disable
221 * updates to a TextImager. This is convenient in code-reuse, occasionally (where
222 * you want to re-use a version of a routine with an UpdateMode, but you will handle
223 * the updating yourself, and you cannot call the routine with the Updatemode directly).
224 *
225 * To avoid the possability (likelihood) of accidentally leaving updates disabled, you cannot set this
226 * directly, but only via a stack-based helper class. Just instantiate a TemporarilySetUpdateMode
227 * to disable updates.
228 #endif
229 */
230 public:
231 nonvirtual UpdateMode GetDefaultUpdateMode () const;
232 nonvirtual UpdateMode RealUpdateMode (UpdateMode updateMode) const;
233
234 protected:
235 virtual void SetDefaultUpdateMode (UpdateMode defaultUpdateMode);
236
237 private:
238 UpdateMode fDefaultUpdateMode;
239
240 public:
241 class TemporarilySetUpdateMode;
242 friend class TemporarilySetUpdateMode;
243
244 public:
245 nonvirtual void Refresh (UpdateMode updateMode = eDefaultUpdate) const;
246 nonvirtual void RefreshWindowRect (const Led_Rect& windowRectArea, UpdateMode updateMode = eDefaultUpdate) const;
247 nonvirtual void Refresh (size_t from, size_t to, UpdateMode updateMode = eDefaultUpdate) const;
248 nonvirtual void Refresh (const Marker* range, UpdateMode updateMode = eDefaultUpdate) const;
249
250 protected:
251 /*
252 @METHOD: TextInteractor::RefreshWindowRect_
253 @DESCRIPTION: <p>pure virtual method called by @'TextInteractor::RefreshWindowRect_'. Generally
254 OVERRIDE in SDK-specific wrapper subclass.</p>
255 <p>The given 'windowRectArea' is given in the same coordinates as the window rect
256 specified by @'TextImager::SetWindowRect': it is not relative to that rectangle.</p>
257 */
258 virtual void RefreshWindowRect_ (const Led_Rect& windowRectArea, UpdateMode updateMode) const = 0;
259
260 /*
261 * When doing "Cut" (and related commands like drag), remove extra surrounding whitespace.
262 * And when doing "Paste" (and related commands like drop), add in any appropriate surrounding whitespace.
263 */
264 public:
265 nonvirtual bool GetSmartCutAndPasteMode () const;
266 nonvirtual void SetSmartCutAndPasteMode (bool smartCutAndPasteMode);
267
268 private:
269 bool fSmartCutAndPasteMode;
270
271 protected:
272 struct SmartCNPInfo {
273 SmartCNPInfo ();
274
275 bool fWordBreakAtSelStart;
276 bool fWordBreakAtSelEnd;
277 };
278
279 protected:
280 nonvirtual bool LooksLikeSmartPastableText (const Led_tChar* text, size_t nTextTChars, SmartCNPInfo* smartCNPInfo) const;
281 nonvirtual void OptionallyAddExtraSpaceForSmartCutAndPasteModeAdds (size_t selStart, const SmartCNPInfo& smartCNPInfo);
282 nonvirtual void OptionallyExpandSelectionForSmartCutAndPasteModeDeletes (size_t* selStart, size_t* selEnd);
283
284 public:
285 virtual void SetSelectionShown (bool shown) override;
286 virtual void SetSelectionShown (bool shown, UpdateMode updateMode);
287
288 public:
289 nonvirtual void ScrollToSelection (UpdateMode updateMode = eDefaultUpdate, bool forceShowSelectionEndpoint = false);
290
291 protected:
292 virtual void HookLosingTextStore () override;
293 nonvirtual void HookLosingTextStore_ ();
294 virtual void HookGainedNewTextStore () override;
295 nonvirtual void HookGainedNewTextStore_ ();
296
297 protected:
298 /*
299 * Mouse clicks.
300 */
301 virtual bool ProcessSimpleClick (Led_Point clickedAt, unsigned clickCount, bool extendSelection, size_t* dragAnchor);
302
303 public:
304 nonvirtual unsigned GetCurClickCount () const;
305 nonvirtual void SetCurClickCount (unsigned curClickCount, Foundation::Time::TimePointSeconds lastClickAt);
306
307 protected:
308 nonvirtual void IncrementCurClickCount (Foundation::Time::TimePointSeconds lastClickAt);
309 nonvirtual void UpdateClickCount (Foundation::Time::TimePointSeconds clickAtTime, const Led_Point& clickAtLocation);
310 virtual bool ClickTimesAreCloseForDoubleClick (Foundation::Time::TimePointSeconds thisClick);
311 virtual bool PointsAreCloseForDoubleClick (const Led_Point& p);
312
313 private:
314 unsigned fClickCount;
315 Foundation::Time::TimePointSeconds fLastClickedAt{};
316 Led_Point fLastMouseDownAt;
317
318 protected:
319 virtual void WhileSimpleMouseTracking (Led_Point newMousePos, size_t dragAnchor);
320
321 protected:
322 virtual void WhileTrackingConstrainSelection (size_t* selStart, size_t* selEnd);
323 virtual void WhileTrackingConstrainSelection_ForWholeWords (size_t* selStart, size_t* selEnd);
324 virtual void WhileTrackingConstrainSelection_ForWholeRows (size_t* selStart, size_t* selEnd);
325
326 public:
327 virtual size_t GetCharAtClickLocation (const Led_Point& where) const;
328
329 public:
330 nonvirtual bool IsWholeWindowInvalid () const;
331
332 virtual void Draw (const Led_Rect& subsetToDraw, bool printing) override;
333
334 protected:
335 nonvirtual void NoteWholeWindowIsInvalid (); // be very careful calling this - be sure its really true!
336 nonvirtual void NoteWindowPartiallyUpdated ();
337
338 private:
339 bool fWholeWindowInvalid;
340
341 public:
342 /*
343 @CLASS: TextInteractor::CannotUpdateNow
344 @DESCRIPTION: <p>Can be thrown indirectly by @'TextInteractor::Update' or @'TextInteractor::UpdateWindowRect'
345 calls if updates are for some reason (perhaps temporarily) unavailable. Can usually be safely
346 ignored.</p>
347 */
348 class CannotUpdateNow {};
349 nonvirtual void Update (bool ignoreCannotUpdateNowErrors = true) const;
350 nonvirtual void UpdateWindowRect (const Led_Rect& windowRectArea, bool ignoreCannotUpdateNowErrors = true) const;
351
352 protected:
353 // These are to be overriden in the actual class library mixin to hook into its
354 // update mechanism.
355 virtual void UpdateWindowRect_ (const Led_Rect& windowRectArea) const = 0;
356
357 public:
358 nonvirtual bool GetUseSecondaryHilight () const;
359 nonvirtual void SetUseSecondaryHilight (bool useSecondaryHilight);
360
361 private:
362 bool fUseSecondaryHilight;
363
364 protected:
365 virtual void DrawBefore (const Led_Rect& subsetToDraw, bool printing);
366 virtual void DrawAfter (const Led_Rect& subsetToDraw, bool printing);
367
368 /*
369 * Overrides to add optional UpdateMode argument.
370 */
371 public:
372 virtual void SetSelection (size_t start, size_t end) override;
373 nonvirtual void SetSelection (size_t start, size_t end, UpdateMode updateMode);
374 nonvirtual void SetTopRowInWindow (size_t newTopRow, UpdateMode updateMode = eDefaultUpdate);
375 nonvirtual void ScrollByIfRoom (ptrdiff_t downBy, UpdateMode updateMode = eDefaultUpdate);
376 nonvirtual void ScrollSoShowing (size_t markerPos, size_t andTryToShowMarkerPos = 0, UpdateMode updateMode = eDefaultUpdate);
377 nonvirtual void SetDefaultFont (const IncrementalFontSpecification& defaultFont, UpdateMode updateMode = eDefaultUpdate);
378 nonvirtual void SetWindowRect (const Led_Rect& windowRect, UpdateMode updateMode = eDefaultUpdate);
379 virtual void SetHScrollPos (CoordinateType hScrollPos) override;
380 nonvirtual void SetHScrollPos (CoordinateType hScrollPos, UpdateMode updateMode);
381
382 /*
383 * Same as SetTopRowInWindow, but uses a marker position instead of a row#. This can be MUCH
384 * more efficient, since it doesn't force word-wrapping in subclasses which support that.
385 */
386 public:
387 virtual void SetTopRowInWindowByMarkerPosition (size_t markerPos, UpdateMode updateMode = eDefaultUpdate) = 0;
388
389 public:
390 nonvirtual bool GetUseBitmapScrollingOptimization () const;
391 nonvirtual void SetUseBitmapScrollingOptimization (bool useBitmapScrollingOptimization);
392
393 private:
394 bool fUseBitmapScrollingOptimization;
395
396 public:
397 nonvirtual bool GetSuppressTypedControlCharacters () const;
398 nonvirtual void SetSuppressTypedControlCharacters (bool suppressTypedControlCharacters);
399
400 private:
401 bool fSuppressTypedControlCharacters;
402
403 public:
404 /*
405 @CLASS: TextInteractor::InteractiveUpdadeMode
406 @DESCRIPTION: <p>Update modes used with @'TextInteractor::InteractiveModeUpdater' and
407 @'TextInteractor::CheckIfCurrentUpdateIsInteractive' to see if a given update is
408 interactive. This can be used to distinguish user text changes (which might be disallowed)
409 from code-based text changes (which a users logic might want to allow).</p>
410 */
411 enum InteractiveUpdadeMode {
412 eInteractiveUpdateMode,
413 eNonInteractiveUpdateMode,
414 eIndeterminateInteractiveUpdateMode
415 };
416 nonvirtual InteractiveUpdadeMode GetInteractiveUpdateMode () const;
417 nonvirtual void SetInteractiveUpdateMode (InteractiveUpdadeMode interactive);
418 nonvirtual bool CheckIfCurrentUpdateIsInteractive () const;
419
420 private:
421 InteractiveUpdadeMode fInteractiveUpdadeMode;
422
423 public:
424 class InteractiveModeUpdater;
425
426 protected:
427 class PreScrollInfo;
428 nonvirtual void PreScrollHelper (UpdateMode updateMode, PreScrollInfo* preScrollInfo);
429 nonvirtual void PostScrollHelper (PreScrollInfo preScrollInfo);
430
431 public:
432 virtual void Replace (size_t from, size_t to, const Led_tChar* withWhat, size_t withWhatCharCount, UpdateMode updateMode = eDefaultUpdate);
433
434 protected:
435 class PreReplaceInfo;
436 virtual void PreReplace (size_t from, size_t to, size_t withWhatCharCount, UpdateMode updateMode, PreReplaceInfo* preReplaceInfo);
437 virtual void PostReplace (PreReplaceInfo& preReplaceInfo);
438 virtual void AbortReplace (PreReplaceInfo& preReplaceInfo);
439 virtual void ExpandedFromAndToInPostReplace (size_t from, size_t newTo, size_t stableTypingRegionStart,
440 size_t stableTypingRegionEnd, size_t startPositionOfRowWhereReplaceBegins,
441 size_t startPositionOfRowAfterReplaceEnds, size_t* expandedFrom, size_t* expandedTo);
442
443 protected:
444 // NB: PreReplaceInfo declared here instead of outside TextInteractor class cuz an instance is
445 // a data member of TextInteractor.
446 class PreReplaceInfo {
447 public:
448 PreReplaceInfo ();
449 ~PreReplaceInfo (); // must get destroyed before owned fTextInteractor, and must either call
450 // PostReplace or AbortReplace or ~PreReplaceInfo before ever losing
451 // fTextInteractor's TextStore...
452
453 public:
454 nonvirtual UpdateMode GetUpdateMode () const;
455 nonvirtual size_t GetFrom () const;
456 nonvirtual size_t GetTo () const;
457
458 private:
459 TextInteractor* fTextInteractor;
460 UpdateMode fUpdateMode;
461 size_t fFrom;
462 size_t fTo;
463 size_t fWithWhatCharCount;
464 Marker fBoundingUpdateMarker;
465 DistanceType fBoundingUpdateHeight;
466 DistanceType fStableTypingRegionHeight;
467
468 private:
469 friend void TextInteractor::PreReplace (size_t from, size_t to, size_t withWhatCharCount, UpdateMode updateMode, PreReplaceInfo* preReplaceInfo);
470 friend void TextInteractor::PostReplace (PreReplaceInfo& preReplaceInfo);
471 friend void TextInteractor::AbortReplace (PreReplaceInfo& preReplaceInfo);
472 };
473
474 /*
475 * Simply calls 'Replace ()'. Only purpose is that it is sometimes convenient to OVERRIDE in just
476 * one place to filter user typing/text updates. And not have to worry about if the particular
477 * bottleneck routine also gets used for 'programming-sourced' text updates. So all typing, and
478 * user-insertions from things like paste (things you might want to validate) go through this
479 * procedure. And you neededn't OVERRIDE 'Replace' itself, unless your refinements are intended to
480 * apply even to programming-based text updates. NB: text updates stemming from apple-events/OLE
481 * automation are considered 'user-updates' - and so vector through here. This is because they
482 * would likely want to be validated.
483 ** DOCS INVALID - MEANING OF InteractiveReplace() REVISED
484 */
485 public:
486 virtual void InteractiveReplace (const Led_tChar* withWhat, size_t withWhatCharCount, UpdateMode updateMode = eDefaultUpdate);
487
488 protected:
489 nonvirtual void InteractiveReplace_ (size_t from, size_t to, const Led_tChar* withWhat, size_t withWhatCharCount,
490 bool updateCursorPosition = true, bool validateTextForCharsetConformance = true,
491 UpdateMode updateMode = eDefaultUpdate);
492
493 protected:
494 virtual bool InteractiveReplaceEarlyPostReplaceHook (size_t withWhatCharCount);
495
496 // utilities to help with undo
497 public:
498 virtual void PreInteractiveUndoHelper (InteractiveReplaceCommand::SavedTextRep** beforeRep, size_t regionStart, size_t regionEnd,
499 size_t selStart, size_t selEnd);
500 virtual void PostInteractiveUndoHelper (InteractiveReplaceCommand::SavedTextRep** beforeRep, size_t startOfInsert,
501 size_t endOfInsert, const SDKString& cmdName);
502 virtual void PostInteractiveSimpleCharInsertUndoHelper (InteractiveReplaceCommand::SavedTextRep** beforeRep, size_t startOfInsert,
503 size_t endOfInsert, const SDKString& cmdName);
504 virtual void PostInteractiveUndoPostHelper (InteractiveReplaceCommand::SavedTextRep** beforeRep,
505 InteractiveReplaceCommand::SavedTextRep** afterRep, size_t startOfInsert, const SDKString& cmdName);
506
507 protected:
508 virtual InteractiveReplaceCommand::SavedTextRep* InteractiveUndoHelperMakeTextRep (size_t regionStart, size_t regionEnd,
509 size_t selStart, size_t selEnd);
510
511 protected:
512 nonvirtual void OnUndoCommand ();
513 nonvirtual void OnRedoCommand ();
514
515 // Utility routine for lots of editing cases - like backspace, cursor arrows, etc...
516 public:
517 enum CursorMovementAction {
518 eCursorDestroying,
519 eCursorMoving,
520 eCursorExtendingSelection
521 };
522
523 protected:
524 virtual void DoSingleCharCursorEdit (CursorMovementDirection direction, CursorMovementUnit movementUnit, CursorMovementAction action,
525 UpdateMode updateMode = eDefaultUpdate, bool scrollToSelection = true);
526
527 public:
528 virtual void AboutToUpdateText (const UpdateInfo& updateInfo) override;
529 virtual void DidUpdateText (const UpdateInfo& updateInfo) noexcept override;
530
531 private:
532 PreReplaceInfo fTmpPreReplaceInfo;
533 TextInteractor* fDoingUpdateModeReplaceOn;
534
535 // Clipboard commands
536 public:
537 virtual void OnCutCommand ();
538 virtual void OnCopyCommand ();
539 virtual void OnPasteCommand ();
540 virtual void OnClearCommand ();
541
542 // helper function for implementing OnCopyCommand
543 protected:
544#if qAccessCheckAcrossInstancesSometimesWrong
545 public:
546#endif
547 virtual bool OnCopyCommand_Before ();
548 virtual void OnCopyCommand_After ();
549 virtual void OnCopyCommand_CopyFlavors ();
550
551 // helper function, to share code between this and subclasses which need different paste behavior
552 protected:
553#if qAccessCheckAcrossInstancesSometimesWrong
554 public:
555#endif
556 virtual bool ShouldEnablePasteCommand () const;
557 virtual bool OnPasteCommand_Before ();
558 virtual void OnPasteCommand_After ();
559 virtual void OnPasteCommand_PasteBestFlavor ();
560 virtual void OnPasteCommand_PasteFlavor_Specific (Led_ClipFormat format);
561
562 protected:
563 nonvirtual bool PasteLooksLikeSmartCNP (SmartCNPInfo* scnpInfo) const;
564
565 public:
566 virtual void OnSelectAllCommand ();
567
568 // Drag & Drop support
569 protected:
570 virtual bool CanAcceptFlavor (Led_ClipFormat clipFormat) const;
571
572 // Internalizing
573 public:
574 virtual void InternalizeBestFlavor (ReaderFlavorPackage& flavorPackage, bool updateCursorPosition = true, bool autoScroll = true,
575 UpdateMode updateMode = eDefaultUpdate);
576 virtual void InternalizeFlavor_Specific (ReaderFlavorPackage& flavorPackage, Led_ClipFormat format, bool updateCursorPosition = true,
577 bool autoScroll = true, UpdateMode updateMode = eDefaultUpdate);
578
579 public:
580 nonvirtual shared_ptr<FlavorPackageInternalizer> GetInternalizer () const;
581 nonvirtual void SetInternalizer (const shared_ptr<FlavorPackageInternalizer>& i);
582
583 private:
584 shared_ptr<FlavorPackageInternalizer> fInternalizer;
585
586 protected:
587 virtual shared_ptr<FlavorPackageInternalizer> MakeDefaultInternalizer ();
588 virtual void HookInternalizerChanged ();
589
590 // Externalizing
591 public:
592 virtual void ExternalizeFlavors (WriterFlavorPackage& flavorPackage);
593 virtual void ExternalizeBestFlavor (WriterFlavorPackage& flavorPackage);
594
595 public:
596 nonvirtual shared_ptr<FlavorPackageExternalizer> GetExternalizer () const;
597 nonvirtual void SetExternalizer (const shared_ptr<FlavorPackageExternalizer>& e);
598
599 private:
600 shared_ptr<FlavorPackageExternalizer> fExternalizer;
601
602 protected:
603 virtual shared_ptr<FlavorPackageExternalizer> MakeDefaultExternalizer ();
604 virtual void HookExternalizerChanged ();
605
606 // Notifications
607 public:
608 class BadUserInput;
609 virtual void OnBadUserInput (); // called - for example - when user types bad SJIS - default is to sysbeep()
610
611 // Scrollbar support
612 public:
613 enum VHSelect {
614 v,
615 h,
616 eFirst = v,
617 eLast = h
618 };
619 enum ScrollBarType {
620 eScrollBarNever,
621 eScrollBarAsNeeded,
622 eScrollBarAlways
623 };
624 nonvirtual ScrollBarType GetScrollBarType (VHSelect vh) const;
625 virtual void SetScrollBarType (VHSelect vh, ScrollBarType scrollBarType);
626
627 protected:
628 nonvirtual void SetScrollBarType_ (VHSelect vh, ScrollBarType scrollBarType);
629
630 private:
631 ScrollBarType fScrollBarType[2];
632
633 /*
634 * Fancy support for delayed scrollbar updatating...
635 */
636 public:
637 virtual void InvalidateScrollBarParameters () override;
638
639 protected:
640 nonvirtual void InvalidateScrollBarParameters_ ();
641 virtual void UpdateScrollBars ();
642 nonvirtual void UpdateScrollBars_ (); // must be called cuz marks sbar parameters valid
643 private:
644 bool fScrollBarParamsValid;
645
646 /*
647 * Helper for implementing scrolling.
648 */
649 public:
650 virtual bool DelaySomeForScrollBarClick ();
651
652 private:
653 Foundation::Time::TimePointSeconds fLastScrolledAt{0s};
654
655 public:
656 nonvirtual bool GetCaretShown () const;
657 nonvirtual void SetCaretShown (bool shown);
658
659 private:
660 bool fCaretShown; // caret is active (though possibly not REALLY shown since drawn in
661 // off state...
662
663 public:
664 virtual bool GetCaretShownSituation () const;
665
666 public:
667 nonvirtual bool GetCaretShownAfterPos () const;
668 nonvirtual void SetCaretShownAfterPos (bool shownAfterPos);
669
670 protected:
671 virtual Led_Rect CalculateCaretRect () const;
672
673 // Can be overriden to update other things like IME position
674 protected:
675 virtual void InvalidateCaretState ();
676
677 protected:
678 bool fLeftSideOfSelectionInteresting; // Occasionally (like in ScrollToSelection ()) it is helpful to know
679 // which end of the selection the user is most interseted in seeing.
680 // Also - we might - for some UI's take this into account in other
681 // places like if we extend one side of a selection, or reduce the
682 // other. Also used in cursoring for extended selection. Must be updated
683 // in subclasses for things like mouse dragging...
684 private:
685 bool fCaretShownAfterPos; // If true show after, else before
686
687 public:
688 virtual void OnTypedNormalCharacter (Led_tChar theChar, bool optionPressed, bool shiftPressed, bool commandPressed,
689 bool controlPressed, bool altKeyPressed);
690
691 /*
692 * Query of the windowing system if there are any pending keystrokes.
693 */
694 protected:
695 virtual bool QueryInputKeyStrokesPending () const = 0;
696
697 protected:
698 nonvirtual void UpdateIfNoKeysPending (); // utility
699
700#if qStroika_Foundation_Common_Platform_MacOS || qStroika_FeatureSupported_XWindows
701 public:
702 static float GetTickCountBetweenBlinks ();
703#endif
704
705 private:
706 friend class SuppressCommandBreaksContext;
707 };
708
709 /*
710 @CLASS: TextInteractor::SuppressCommandBreaksContext
711 @ACCESS: public
712 @DESCRIPTION: <p>When one of these is created on the stack for the @'TextInteractor' ti, then
713 commands on that TextInteractor to @'TextInteractor::BreakInGroupedCommands ()' are
714 ignored.</p>
715 */
716 class TextInteractor::SuppressCommandBreaksContext {
717 public:
718 SuppressCommandBreaksContext (TextInteractor& ti);
719 ~SuppressCommandBreaksContext ();
720
721 private:
722 TextInteractor& fTextInteractor;
723 bool fOldVal;
724 };
725
726 /*
727 @CLASS: TextInteractor::CommandNames
728 @DESCRIPTION: <p>Command names for each of the user-visible commands produced by the @'TextInteractor' module.
729 This name is used used in the constructed Undo command name, as
730 in, "Undo Paste". You can replace this name with whatever you like.
731 You change this value with @'TextInteractor::SetCommandNames'.</p>
732 <p> The point of this is to allow for different UI-language localizations,
733 without having to change Led itself.</p>
734 <p>See also @'TextInteractor::GetCommandNames'.</p>
735 <p>See also @'WordProcessor::CommandNames'.</p>
736 */
737 struct TextInteractor::CommandNames {
738 SDKString fTypingCommandName;
739 SDKString fCutCommandName;
740 SDKString fClearCommandName;
741 SDKString fPasteCommandName;
742 SDKString fUndoFormatString;
743 SDKString fRedoFormatString;
744 SDKString fReplaceCommandName;
745 SDKString fReplaceAllCommandName;
746 SDKString fReplaceAllInSelectionCommandName;
747 };
748
749 /*
750 @CLASS: TextInteractor::CommandUpdater
751 @DESCRIPTION: <p></p>
752 */
753 class TextInteractor::CommandUpdater {
754 public:
755 using CommandNumber = TextInteractor::CommandNumber;
756
757 public:
758 virtual CommandNumber GetCmdID () const = 0;
759 virtual bool GetEnabled () const = 0;
760 virtual void SetEnabled (bool enabled) = 0;
761 virtual void SetChecked (bool checked) = 0;
762 virtual void SetText (const SDKChar* text) = 0;
763 };
764
765 /*
766 @CLASS: TextInteractor::DialogSupport
767 @DESCRIPTION: <p></p>
768 */
769 class TextInteractor::DialogSupport {
770 public:
771 using CommandNumber = TextInteractor::CommandNumber;
772
773 public:
774 virtual void DisplayFindDialog (Led_tString* findText, const vector<Led_tString>& recentFindSuggestions, bool* wrapSearch,
775 bool* wholeWordSearch, bool* caseSensative, bool* pressedOK);
776
777 public:
778 enum ReplaceButtonPressed {
779 eReplaceButton_Cancel,
780 eReplaceButton_Find,
781 eReplaceButton_Replace,
782 eReplaceButton_ReplaceAll,
783 eReplaceButton_ReplaceAllInSelection
784 };
785 virtual ReplaceButtonPressed DisplayReplaceDialog (Led_tString* findText, const vector<Led_tString>& recentFindSuggestions,
786 Led_tString* replaceText, bool* wrapSearch, bool* wholeWordSearch, bool* caseSensative);
787
788 public:
789 class SpellCheckDialogCallback;
790 virtual void DisplaySpellCheckDialog (SpellCheckDialogCallback& callback);
791 };
792
793 /*
794 @CLASS: TextInteractor::DialogSupport::SpellCheckDialogCallback
795 @DESCRIPTION: <p>This interface is called by the actual spellcheck dialog implematation back to the implementer
796 of the real spellchecking functionality.</p>
797 */
798 class TextInteractor::DialogSupport::SpellCheckDialogCallback {
799 public:
800 struct MisspellingInfo {
801 Led_tString fUndefinedWord;
802 vector<Led_tString> fSuggestions;
803 };
804
805 public:
806 virtual MisspellingInfo* GetNextMisspelling () = 0;
807
808 public:
809 virtual void DoIgnore () = 0;
810 virtual void DoIgnoreAll () = 0;
811 virtual void DoChange (const Led_tString& changeTo) = 0;
812 virtual void DoChangeAll (const Led_tString& changeTo) = 0;
813 virtual bool AddToDictionaryEnabled () const = 0;
814 virtual void AddToDictionary (const Led_tString& newWord) = 0;
815 virtual void LookupOnWeb (const Led_tString& word) = 0;
816 virtual bool OptionsDialogEnabled () const = 0;
817 virtual void OptionsDialog () = 0;
818 };
819
820 /*
821 @CLASS: TextInteractor::SearchParameters
822 @DESCRIPTION: <p>
823 </p>
824 */
825 class TextInteractor::SearchParameters : public TextStore::SearchParameters {
826 private:
827 using inherited = TextStore::SearchParameters;
828
829 public:
830 SearchParameters ();
831
832 public:
833 vector<Led_tString> fRecentFindStrings;
834 };
835
836 /*
837 @CLASS: TextInteractor::ReplaceParameters
838 @DESCRIPTION: <p>
839 </p>
840 */
841 class TextInteractor::ReplaceParameters {
842 public:
843 ReplaceParameters ();
844
845 public:
846 Led_tString fReplaceWith;
847 };
848
849 /*
850 @CLASS: TextInteractor::UndoableContextHelper
851 @DESCRIPTION: <p>Use this helper class in a context where you are creating/doing an undoable
852 command. This class is a simpler wrapper/helper for @'TextInteractor::PreInteractiveUndoHelper'
853 and @'TextInteractor::PostInteractiveUndoHelper'.</p>
854 <p>A simple example usage would be:<br>
855 <code><pre>
856 UndoableContextHelper undoContext (*this, GetCommandNames ().fClearCommandName, true);
857 {
858 //Actual command guts
859 InteractiveReplace_ (undoContext.GetUndoRegionStart (), undoContext.GetUndoRegionEnd (), LED_TCHAR_OF (""), 0);
860 }
861 undoContext.CommandComplete ();
862 </pre></code>
863 </p>
864 <p>Note - the 'allowSmartCNPExpansion' should generally be true if the undoable action could
865 have invoked smartcutandpaste space additions/removealls. Specifing true expands the region we capture to
866 take this possability into account.
867 </p>
868 */
869 class TextInteractor::UndoableContextHelper {
870 public:
871 using SavedTextRep = InteractiveReplaceCommand::SavedTextRep;
872
873 public:
874 UndoableContextHelper (TextInteractor& ti, const SDKString& cmdName, bool allowSmartCNPExpansion);
875 UndoableContextHelper (TextInteractor& ti, const SDKString& cmdName, size_t regionAndSelStart, size_t regionAndSelEnd, bool allowSmartCNPExpansion);
876 UndoableContextHelper (TextInteractor& ti, const SDKString& cmdName, size_t regionStart, size_t regionEnd, size_t selStart,
877 size_t selEnd, bool allowSmartCNPExpansion);
878 ~UndoableContextHelper ();
879
880 public:
881 nonvirtual void CommandComplete ();
882 nonvirtual void CommandComplete (size_t endOfInsert);
883
884 public:
885 nonvirtual size_t GetUndoRegionStart () const;
886 nonvirtual size_t GetUndoRegionEnd () const;
887
888 public:
889 nonvirtual bool GetSimplePlainTextInsertOptimization () const;
890 nonvirtual void SetSimplePlainTextInsertOptimization (bool simplePlainTextInsertOptimizationFlag);
891
892 private:
893 bool fSimplePlainTextInsertOptimization;
894
895 private:
896 TextInteractor& fTextInteractor;
897 SDKString fCmdName;
898 size_t fSelStart;
899 size_t fSelEnd;
900 SavedTextRep* fBefore;
901 bool fCommandComplete;
902 };
903
904 /*
905 @CLASS: TextInteractor::TemporarilySetUpdateMode
906 @DESCRIPTION: <p>See @'TextInteractor::GetDefaultUpdateMode'.</p>
907 */
908 class TextInteractor::TemporarilySetUpdateMode {
909 public:
910 TemporarilySetUpdateMode (TextInteractor& ti, TextInteractor::UpdateMode tmpUpdateMode);
911 ~TemporarilySetUpdateMode ();
912
913 private:
914 TextInteractor& fTextInteractor;
915 UpdateMode fOldValue;
916
917 private:
918 TemporarilySetUpdateMode (const TemporarilySetUpdateMode&) = delete;
919 TemporarilySetUpdateMode& operator= (const TemporarilySetUpdateMode&) = delete;
920 static void* operator new (size_t); // DONT
921 };
922
923 /*
924 @CLASS: TextInteractor::InteractiveModeUpdater
925 @DESCRIPTION: <p>Calls @'TextInteractor::SetInteractiveUpdateMode' to save/restore the interactive update
926 mode for</p>
927 */
928 class TextInteractor::InteractiveModeUpdater {
929 public:
930 InteractiveModeUpdater (TextInteractor& ti, bool interactive = true);
931 ~InteractiveModeUpdater ();
932
933 private:
934 TextInteractor& fTextInteractor;
935 InteractiveUpdadeMode fSavedMode;
936 };
937
938 /*
939 @CLASS: TextInteractor::PreScrollInfo
940 @DESCRIPTION: <p></p>
941 */
942 class TextInteractor::PreScrollInfo {
943 public:
944 PreScrollInfo ();
945
946 private:
947 UpdateMode fUpdateMode;
948 size_t fOldWindowStart;
949 CoordinateType fOldHScrollPos;
950 bool fTryTodoScrollbits;
951 size_t fOldLastRowStart;
952
953 private:
954 friend void TextInteractor::PreScrollHelper (UpdateMode updateMode, PreScrollInfo* preScrollInfo);
955 friend void TextInteractor::PostScrollHelper (PreScrollInfo preScrollInfo);
956 };
957
958 /*
959 @CLASS: TextInteractor::BadUserInput
960 @DESCRIPTION: <p>See @'TextInteractor::OnBadUserInput'.</p>
961 */
962 class TextInteractor::BadUserInput {};
963
964 /*
965 @CLASS: CommandNumberMapping<TARGET_COMMAND_NUMBER>
966 @DESCRIPTION: <p></p>
967 */
968 template <typename TARGET_COMMAND_NUMBER>
969 class CommandNumberMapping {
970 public:
971 using CommandNumber = TextInteractor::CommandNumber;
972
973 public:
974 CommandNumberMapping ();
975 ~CommandNumberMapping ();
976
977 public:
978 static CommandNumberMapping<TARGET_COMMAND_NUMBER>& Get ();
979
980 public:
981 nonvirtual void AddAssociation (TARGET_COMMAND_NUMBER externalCommandNumber, CommandNumber internalCommandNumber);
982 nonvirtual void AddRangeAssociation (TARGET_COMMAND_NUMBER externalRangeStart, TARGET_COMMAND_NUMBER externalRangeEnd,
983 CommandNumber internalRangeStart, CommandNumber internalRangeEnd);
984 virtual CommandNumber Lookup (TARGET_COMMAND_NUMBER tcn) const;
985 virtual TARGET_COMMAND_NUMBER ReverseLookup (CommandNumber cmdNum) const;
986
987 private:
988 using MAP_TYPE = map<TARGET_COMMAND_NUMBER, CommandNumber>;
989 MAP_TYPE fMap;
990 struct RangeElt {
991 pair<TARGET_COMMAND_NUMBER, TARGET_COMMAND_NUMBER> fExternalCmds;
992 pair<CommandNumber, CommandNumber> fInternalCmds;
993 };
994 using RANGE_VEC_TYPE = vector<RangeElt>;
995 RANGE_VEC_TYPE fRanges;
996
997 private:
998 static CommandNumberMapping<TARGET_COMMAND_NUMBER>* sThe;
999 };
1000
1001 /*
1002 @CLASS: SimpleCommandUpdater
1003 @BASES: TextInteractor::CommandUpdater
1004 @DESCRIPTION: <p></p>
1005 */
1006 class SimpleCommandUpdater : public TextInteractor::CommandUpdater {
1007 public:
1008 SimpleCommandUpdater (CommandNumber cmdNum);
1009
1010 public:
1011 virtual CommandNumber GetCmdID () const override;
1012 virtual bool GetEnabled () const override;
1013 virtual void SetEnabled (bool enabled) override;
1014 virtual void SetChecked (bool checked) override;
1015 virtual void SetText (const SDKChar* text) override;
1016
1017 public:
1018 CommandNumber fCommandNumber;
1019 bool fEnabled;
1020 bool fChecked;
1021 SDKString fText;
1022 };
1023
1024 DISABLE_COMPILER_MSC_WARNING_START (4250) // inherits via dominance warning
1025 /*
1026 @CLASS: TrivialImager_Interactor<TEXTSTORE,IMAGER>
1027 @DESCRIPTION: <p>Handy little template, if you want to use the power of Led, but just to wrap a particular imager,
1028 in a localized, one-time fasion, say todo printing, or some such. Not for interactors.</p>
1029 <p>The usuage can be as simple as:
1030 <code>
1031 void SomeAppDrawCall (Tablet* t, const Led_Rect& r)
1032 {
1033 TrivialImager_Interactor<ChunkedArrayTextStore, WordProcessor> (t, r, LED_TCHAR_OF ("Hi mom")).Draw ();
1034 }
1035 </code>
1036 </p>
1037 <p>See also @'TrivialImager<TEXTSTORE,IMAGER>', and @'TrivialWordWrappedImager<TEXTSTORE,IMAGER>'.</p>
1038 */
1039 template <typename TEXTSTORE, typename IMAGER>
1040 class TrivialImager_Interactor : public TrivialImager<TEXTSTORE, IMAGER> {
1041 private:
1042 using inherited = TrivialImager<TEXTSTORE, IMAGER>;
1043
1044 public:
1045 TrivialImager_Interactor (Tablet* t)
1046 : inherited (t)
1047 {
1048 }
1049 TrivialImager_Interactor (Tablet* t, Led_Rect bounds, const Led_tString& initialText = LED_TCHAR_OF (""))
1050 : inherited (t)
1051 {
1052 // Kooky I cannot just call base class CTOR that does all this - but then it invokes calls to RefreshWindowRect_ etc, before
1053 // THIS CTOR is done, so they call pure-virtual version!
1054 this->SnagAttributesFromTablet ();
1055 this->SetWindowRect (bounds);
1056 this->GetTextStore ().Replace (0, 0, initialText.c_str (), initialText.length ());
1057 }
1058
1059 // In case the imager is a TextInteractor - provide dummy implementations...
1060 public:
1061 using UpdateMode = typename IMAGER::UpdateMode;
1062 virtual bool QueryInputKeyStrokesPending () const override
1063 {
1064 return false;
1065 };
1066 virtual void RefreshWindowRect_ ([[maybe_unused]] const Led_Rect& windowRectArea, [[maybe_unused]] UpdateMode updateMode) const override
1067 {
1068 }
1069 virtual void UpdateWindowRect_ ([[maybe_unused]] const Led_Rect& windowRectArea) const override
1070 {
1071 }
1072 };
1073 DISABLE_COMPILER_MSC_WARNING_END (4250) // inherits via dominance warning
1074#endif
1075
1076}
1077
1078/*
1079 ********************************************************************************
1080 ***************************** Implementation Details ***************************
1081 ********************************************************************************
1082 */
1083#include "TextInteractor.inl"
1084
1085#endif /*_Stroika_Frameworks_Led_TextInteractor_h_*/
conditional_t< qTargetPlatformSDKUseswchar_t, wchar_t, char > SDKChar
Definition SDKChar.h:71
basic_string< SDKChar > SDKString
Definition SDKString.h:38