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