Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
MultiRowTextImager.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Frameworks_Led_MultiRowTextImager_h_
5#define _Stroika_Frameworks_Led_MultiRowTextImager_h_ 1
6
7#include "Stroika/Frameworks/StroikaPreComp.h"
8
9/*
10@MODULE: MultiRowTextImager
11@DESCRIPTION:
12 <p>MultiRowTextImager is a @'TextImager' which supports having partition elements made up of multirow text.</p>
13
14 */
15
16#include <climits> // for UINT_MAX
17#include <cstring>
18
19#include "LineBasedPartition.h"
20#include "PartitioningTextImager.h"
21
22namespace Stroika::Frameworks::Led {
23
24#if qStroika_Frameworks_Led_SupportGDI
25 /*
26 @CLASS: MultiRowTextImager
27 @BASES: @'PartitioningTextImager'
28 @DESCRIPTION:
29 <p>A @'PartitioningTextImager' which supports the notion of having multiple rows of text per line.</p>
30 <p>NB: Although this class properly supports the APIs for @'PartitioningTextImager', it has a
31 limitation, based on its historical implementation. It assumes that there is a one-to-one
32 correspondance between its Partition and the TextImager, and that this Partition is (or subclasses from
33 @'MultiRowTextImager::MultiRowPartition').</p>
34 <p>This limitation is partly (largely) based on the fact that we use the trick of piggybacking row-wrap
35 information on the partition markers themselves. A future version of this class might keep the per-row information
36 in a MarkerCover, or some such other data structure.</p>
37 */
38 class MultiRowTextImager : public PartitioningTextImager {
39 protected:
40 MultiRowTextImager () = default;
41 virtual ~MultiRowTextImager ();
42
43 private:
44 MultiRowTextImager (const MultiRowTextImager&) = delete;
45 nonvirtual void operator= (const MultiRowTextImager&) = delete;
46
47 private:
48 using inherited = PartitioningTextImager;
49
50 protected:
51 virtual void HookLosingTextStore () override;
52 nonvirtual void HookLosingTextStore_ ();
53 virtual void HookGainedNewTextStore () override;
54 nonvirtual void HookGainedNewTextStore_ ();
55
56 public:
57 class PartitionElementCacheInfo;
58
59 protected:
60 virtual void SetPartition (const PartitionPtr& partitionPtr) override;
61
62 public:
63 virtual PartitionPtr MakeDefaultPartition () const override;
64
65 public:
66 /*
67 @CLASS: MultiRowTextImager::RowReference
68 @DESCRIPTION:
69 <p>A utility class to represent a row. It is a struct with a parition marker, and a row number.
70 These things are NOT long-lived. And shouldn't be saved anyplace, as no attempt is made to keep
71 them automaticlly up to date as the text is modified.
72 They are just a convenient, short-hand way to navigate through rows of text.</p>
73 */
74 class RowReference {
75 public:
76 RowReference (const RowReference& from) = default;
77 RowReference (PartitionMarker* partitionMarker, size_t subRow);
78
79 private:
80 RowReference (); // left undefined to assure never called...
81 public:
82 nonvirtual RowReference& operator= (const RowReference& rhs);
83
84 public:
85 nonvirtual PartitionMarker* GetPartitionMarker () const;
86 nonvirtual size_t GetSubRow () const;
87
88 public:
89 nonvirtual bool operator== (RowReference rhs) const;
90
91 private:
92 PartitionMarker* fPartitionMarker;
93 size_t fSubRow;
94 };
95 friend class RowReference;
96
97 public:
98 nonvirtual PartitionElementCacheInfo GetPartitionElementCacheInfo (Partition::PartitionMarker* pm) const;
99 nonvirtual PartitionElementCacheInfo GetPartitionElementCacheInfo (RowReference row) const;
100
101 private:
102 class PMInfoCacheMgr;
103 unique_ptr<PMInfoCacheMgr> fPMCacheMgr;
104
105 // Row Reference support routines...
106 public:
107 nonvirtual bool GetNextRowReference (RowReference* adjustMeInPlace) const; // return true if there is a next, and false if at end
108 nonvirtual bool GetPreviousRowReference (RowReference* adjustMeInPlace) const; // return true if there is a previous, and false if at the beginning
109
110 // NB: if ith==1, that means do NOTHING - for convenience...
111 nonvirtual bool GetIthRowReferenceFromHere (RowReference* adjustMeInPlace, ptrdiff_t ith) const; // return true if there is an ith, and false if we run off end... (ith==0 implies no change, < 0 means go back)
112 nonvirtual RowReference GetIthRowReferenceFromHere (RowReference fromHere, ptrdiff_t ith) const; // ERROR if ith doesn't exist... (ith==0 implies no change, < 0 means go back)
113 nonvirtual RowReference GetIthRowReference (size_t ith) const; // ERROR if ith doesn't exist...(1 th is first row)
114
115 nonvirtual size_t GetRowNumber (RowReference rowRef) const; // Use of row numbers is discouraged, but this routine
116 // can be helpful in implementing those APIs anyhow
117
118 nonvirtual size_t CountRowDifference (RowReference lhs, RowReference rhs) const;
119 nonvirtual size_t CountRowDifferenceLimited (RowReference lhs, RowReference rhs, size_t limit) const;
120
121 /*
122 * Window/Scrolling support.
123 */
124 public:
125 virtual size_t GetTopRowInWindow () const override;
126 virtual size_t GetTotalRowsInWindow () const override;
127 virtual size_t GetLastRowInWindow () const override;
128 virtual void SetTopRowInWindow (size_t newTopRow) override;
129 virtual size_t GetMarkerPositionOfStartOfWindow () const override;
130 virtual size_t GetMarkerPositionOfEndOfWindow () const override;
131 virtual size_t GetMarkerPositionOfStartOfLastRowOfWindow () const override;
132 virtual ptrdiff_t CalculateRowDeltaFromCharDeltaFromTopOfWindow (long deltaChars) const override;
133 virtual ptrdiff_t CalculateCharDeltaFromRowDeltaFromTopOfWindow (ptrdiff_t deltaRows) const override;
134 virtual void ScrollByIfRoom (ptrdiff_t downByRows); // if downBy negative then up
135 // OK to ask to scroll further
136 // than allowed - return true
137 // if any scrolling (not necesarily
138 // same amont requested) done
139 public:
140 virtual void ScrollSoShowing (size_t markerPos, size_t andTryToShowMarkerPos = 0) override;
141
142 protected:
143 nonvirtual RowReference GetTopRowReferenceInWindow () const;
144 nonvirtual RowReference GetLastRowReferenceInWindow () const;
145 virtual void SetTopRowInWindow (RowReference row);
146
147 protected:
148 nonvirtual void SetTopRowInWindow_ (RowReference row); // just sets the fields without any hook functions
149 // getting called. This is important sometimes when
150 // it would be unsafe for subclasses to get a chance
151 // to call methods while our data structures are not
152 // not completely up-to-date.
153
154 protected:
155 virtual void AssureWholeWindowUsedIfNeeded () override;
156
157 public:
158 virtual Led_Rect GetCharLocation (size_t afterPosition) const override;
159 virtual size_t GetCharAtLocation (const Led_Point& where) const override;
160 virtual Led_Rect GetCharWindowLocation (size_t afterPosition) const override;
161 virtual size_t GetCharAtWindowLocation (const Led_Point& where) const override;
162
163 virtual size_t GetStartOfRow (size_t rowNumber) const override;
164 virtual size_t GetStartOfRowContainingPosition (size_t charPosition) const override;
165 virtual size_t GetEndOfRow (size_t rowNumber) const override;
166 virtual size_t GetEndOfRowContainingPosition (size_t charPosition) const override;
167 virtual size_t GetRealEndOfRow (size_t rowNumber) const override;
168 virtual size_t GetRealEndOfRowContainingPosition (size_t charPosition) const override;
169 virtual size_t GetRowContainingPosition (size_t charPosition) const override;
170 virtual size_t GetRowCount () const override;
171 virtual Led_Rect GetCharLocationRowRelativeByPosition (size_t afterPosition, size_t positionOfTopRow, size_t maxRowsToCheck) const override;
172
173 public:
174 nonvirtual size_t GetStartOfRow (RowReference row) const;
175 nonvirtual size_t GetEndOfRow (RowReference row) const;
176 nonvirtual size_t GetRealEndOfRow (RowReference row) const;
177 nonvirtual RowReference GetRowReferenceContainingPosition (size_t charPosition) const;
178 nonvirtual size_t GetRowLength (RowReference row) const;
179
180 public:
181 virtual DistanceType GetRowHeight (size_t rowNumber) const override;
182 nonvirtual DistanceType GetRowHeight (RowReference row) const;
183
184 public:
185 virtual DistanceType GetRowRelativeBaselineOfRowContainingPosition (size_t charPosition) const override;
186
187 public:
188 nonvirtual DistanceType GetHeightOfRows (size_t startingRow, size_t rowCount) const;
189 nonvirtual DistanceType GetHeightOfRows (RowReference startingRow, size_t rowCount) const;
190
191 public:
192 virtual void GetStableTypingRegionContaingMarkerRange (size_t fromMarkerPos, size_t toMarkerPos, size_t* expandedFromMarkerPos,
193 size_t* expandedToMarkerPos) const;
194
195 public:
196 virtual void Draw (const Led_Rect& subsetToDraw, bool printing);
197
198 public:
199 virtual void DrawPartitionElement (PartitionMarker* pm, size_t startSubRow, size_t maxSubRow, Tablet* tablet, OffscreenTablet* offscreenTablet,
200 bool printing, const Led_Rect& subsetToDraw, Led_Rect* remainingDrawArea, size_t* rowsDrawn);
201
202 protected:
203 virtual Led_Rect GetCharLocationRowRelative (size_t afterPosition, RowReference topRow, size_t maxRowsToCheck = UINT_MAX) const;
204 virtual size_t GetCharAtLocationRowRelative (const Led_Point& where, RowReference topRow, size_t maxRowsToCheck = UINT_MAX) const;
205
206 protected:
207 virtual void FillCache (PartitionMarker* pm, PartitionElementCacheInfo& cacheInfo) = 0;
208 virtual DistanceType CalculateInterLineSpace (const PartitionMarker* pm) const;
209
210 protected:
211 virtual bool ContainsMappedDisplayCharacters (const Led_tChar* text, size_t nTChars) const;
212 virtual size_t RemoveMappedDisplayCharacters (Led_tChar* copyText, size_t nTChars) const;
213
214#if 0
215 // Hook to invalidate cached info based on fontmetrics
216 public:
217 virtual void SetDefaultFont (const IncrementalFontSpecification& defaultFont);
218 protected:
219 nonvirtual void SetDefaultFont_ (const IncrementalFontSpecification& /*defaultFont*/); // Merely invalidates font metrics
220#endif
221
222 // To assure our top-line scroll info not left corrupt...
223 protected:
224 virtual void DidUpdateText (const UpdateInfo& updateInfo) noexcept;
225
226 // override to invalidate caches.
227 public:
228 virtual void SetWindowRect (const Led_Rect& windowRect) override;
229
230 protected:
231 virtual void InvalidateAllCaches () override;
232
233 private:
234 nonvirtual RowReference AdjustPotentialTopRowReferenceSoWholeWindowUsed (const RowReference& potentialTopRow);
235 nonvirtual bool PositionWouldFitInWindowWithThisTopRow (size_t markerPos, const RowReference& newTopRow);
236
237 private:
238 PartitionMarker* fTopLinePartitionMarkerInWindow{nullptr};
239 size_t fSubRowInTopLineInWindow{0};
240
241 private:
242 nonvirtual void ReValidateSubRowInTopLineInWindow ();
243
244 // Support for GetTotalRowsInWindow
245 //
246 // Override ComputeRowsThatWouldFitInWindowWithTopRow () to change the policy of how we
247 // pack rows into a window
248 private:
249 mutable size_t fTotalRowsInWindow{0}; // zero means invalid cached - fill cache on call to GetTotalRowsInWindow
250 protected:
251 nonvirtual size_t GetTotalRowsInWindow_ () const;
252 nonvirtual void InvalidateTotalRowsInWindow ();
253 virtual size_t ComputeRowsThatWouldFitInWindowWithTopRow (const RowReference& newTopRow) const;
254
255 private:
256 friend class PMInfoCacheMgr;
257 };
258
259 /*
260 @CLASS: MultiRowTextImager::PartitionElementCacheInfo
261 @DESCRIPTION:
262 <p></p>
263 */
264 class MultiRowTextImager::PartitionElementCacheInfo {
265 public:
266 PartitionElementCacheInfo ();
267
268 public:
269 nonvirtual DistanceType GetPixelHeight () const;
270 nonvirtual size_t GetRowCount () const;
271 nonvirtual size_t PeekRowCount () const;
272 nonvirtual size_t GetLastRow () const;
273 nonvirtual DistanceType GetRowHeight (size_t ithRow) const;
274 nonvirtual size_t GetLineRelativeRowStartPosition (size_t ithRow) const;
275 nonvirtual size_t LineRelativePositionInWhichRow (size_t charPos) const; // ZERO based charPos - ie zero is just before first byte in first row
276
277 public:
278 nonvirtual DistanceType GetInterLineSpace () const;
279 nonvirtual void SetInterLineSpace (DistanceType interlineSpace);
280
281 /*
282 * Word wrapping helper routine.
283 */
284 public:
285 nonvirtual void Clear ();
286 nonvirtual void IncrementRowCountAndFixCacheBuffers (size_t newStart, DistanceType newRowsHeight);
287
288 // These should only be modifed in the FillCache () routine (or its overrides in subclasses)....
289 public:
290 // Note - calling these routines we assert i >= 0, <= fRowCountCache - to increase size of cache
291 // call IncrementRowCountAndFixCacheBuffers ()
292 nonvirtual DistanceType PeekAtRowHeight (size_t ithRow) const;
293 nonvirtual void SetRowHeight (size_t i, DistanceType rowHeight);
294
295 nonvirtual size_t PeekAtRowStart (size_t i) const;
296 nonvirtual void SetRowStart (size_t i, size_t rowStart); // NB: rowStart[1] MUST BE ZERO!!!!
297
298 private:
299 using RowHeight_ = uint16_t;
300 // Don't yet support packed RowStart_ ONLY because we keep array of starts, not nChars in row.
301 // If we switch to that - then we can use unsigned char for this as with the rowHeight guy!!!
302 // LGP 950519
303 using RowStart_ = size_t;
304 enum {
305 kPackRowStartCount = sizeof (RowStart_*) / sizeof (RowStart_)
306 };
307 enum {
308 kPackRowHeightCount = sizeof (RowHeight_*) / sizeof (RowHeight_)
309 };
310
311 private:
312 struct Rep : public Foundation::Memory::UseBlockAllocationIfAppropriate<Rep> {
313 public:
314 Rep ();
315 ~Rep ();
316
317 public:
318 DistanceType fInterlineSpace;
319 DistanceType fPixelHeightCache;
320 size_t fRowCountCache;
321 RowStart_* fRowStartArray;
322 RowHeight_* fRowHeightArray;
323
324 private:
325 Rep (const Rep&) = delete;
326 void operator= (const Rep&) = delete;
327 };
328
329 private:
330 shared_ptr<Rep> fRep;
331
332 private:
333 friend struct Rep;
334 friend class shared_ptr<Rep>;
335 };
336
337 /*
338 @CLASS: MultiRowTextImager::PMInfoCacheMgr
339 @BASES: @'Partition::PartitionWatcher'
340 @DESCRIPTION:
341 <p></p>
342 */
343 class MultiRowTextImager::PMInfoCacheMgr : public Partition::PartitionWatcher {
344 private:
345 using inherited = Partition::PartitionWatcher;
346
347 public:
348 PMInfoCacheMgr (MultiRowTextImager& imager);
349 ~PMInfoCacheMgr ();
350
351 public:
352 nonvirtual MultiRowTextImager::PartitionElementCacheInfo GetPartitionElementCacheInfo (Partition::PartitionMarker* pm) const;
353
354 public:
355 nonvirtual void ClearCache ();
356
357 public:
358 virtual void AboutToSplit (PartitionMarker* pm, size_t at, void** infoRecord) const noexcept override;
359 virtual void DidSplit (void* infoRecord) const noexcept override;
360 virtual void AboutToCoalece (PartitionMarker* pm, void** infoRecord) const noexcept override;
361 virtual void DidCoalece (void* infoRecord) const noexcept override;
362
363 private:
364 nonvirtual void MyMarkerDidUpdateCallback ();
365
366 private:
367 class MyMarker;
368 mutable map<PartitionMarker*, PartitionElementCacheInfo> fPMCache;
369 mutable PartitionMarker* fCurFillCachePM;
370 mutable PartitionElementCacheInfo fCurFillCacheInfo;
371 MultiRowTextImager& fImager;
372 unique_ptr<MyMarker> fMyMarker;
373
374 private:
375 friend class MyMarker;
376 };
377
378 /*
379 @CLASS: MultiRowTextImager::PMInfoCacheMgr::MyMarker
380 @CLASS: Marker
381 @ACCESS: private
382 @DESCRIPTION:
383 <p></p>
384 */
385 class MultiRowTextImager::PMInfoCacheMgr::MyMarker : public Marker {
386 private:
387 using inherited = Marker;
388
389 public:
390 MyMarker (PMInfoCacheMgr& pmInfoCacheMgr);
391
392 protected:
393 virtual void DidUpdateText (const UpdateInfo& updateInfo) noexcept override;
394
395 private:
396 PMInfoCacheMgr& fPMInfoCacheMgr;
397 };
398#endif
399
400}
401
402/*
403 ********************************************************************************
404 ***************************** Implementation Details ***************************
405 ********************************************************************************
406 */
407#include "MultiRowTextImager.inl"
408
409#endif /*_Stroika_Frameworks_Led_MultiRowTextImager_h_*/