Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
MultiRowTextImager.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4
5namespace Stroika::Frameworks::Led {
6
7#if qStroika_Frameworks_Led_SupportGDI
8 /*
9 ********************************************************************************
10 ****************************** MultiRowTextImager ******************************
11 ********************************************************************************
12 */
13 inline void MultiRowTextImager::InvalidateTotalRowsInWindow ()
14 {
15 fTotalRowsInWindow = 0; // zero is sentinel meaning invalid
16 }
17 inline MultiRowTextImager::RowReference MultiRowTextImager::GetTopRowReferenceInWindow () const
18 {
19 RequireNotNull (PeekAtTextStore ()); // Must associate textstore before we can ask for row-references
20 EnsureNotNull (fTopLinePartitionMarkerInWindow);
21 const_cast<MultiRowTextImager*> (this)->ReValidateSubRowInTopLineInWindow ();
22 return (RowReference (fTopLinePartitionMarkerInWindow, fSubRowInTopLineInWindow));
23 }
24 inline size_t MultiRowTextImager::GetTotalRowsInWindow_ () const
25 {
26 if (fTotalRowsInWindow == 0) { // cached value invalid
27 fTotalRowsInWindow = ComputeRowsThatWouldFitInWindowWithTopRow (GetTopRowReferenceInWindow ());
28 }
29 Assert (fTotalRowsInWindow >= 1); // always have at least one row...
30 Assert (fTotalRowsInWindow == ComputeRowsThatWouldFitInWindowWithTopRow (GetTopRowReferenceInWindow ()));
31 return (fTotalRowsInWindow);
32 }
33
34 /*
35 ********************************************************************************
36 ************ MultiRowTextImager::PartitionElementCacheInfo::Rep ****************
37 ********************************************************************************
38 */
39 inline MultiRowTextImager::PartitionElementCacheInfo::Rep::Rep ()
40 : fPixelHeightCache (DistanceType (-1))
41 , fInterlineSpace (0)
42 , fRowCountCache (0)
43 , fRowStartArray (nullptr)
44 , fRowHeightArray (nullptr)
45 {
46 }
47 inline MultiRowTextImager::PartitionElementCacheInfo::Rep::~Rep ()
48 {
49 if (fRowCountCache > kPackRowStartCount + 1) {
50 delete[] fRowStartArray;
51 }
52 if (fRowCountCache > kPackRowHeightCount) {
53 delete[] fRowHeightArray;
54 }
55 }
56
57 /*
58 ********************************************************************************
59 *************** MultiRowTextImager::PartitionElementCacheInfo ******************
60 ********************************************************************************
61 */
62 inline MultiRowTextImager::PartitionElementCacheInfo::PartitionElementCacheInfo ()
63 : fRep (make_shared<Rep> ())
64 {
65 }
66 /*
67 @METHOD: MultiRowTextImager::PartitionElementCacheInfo::GetInterLineSpace
68 @DESCRIPTION: <p>Get the interline space associated with a partition. Each partition can
69 have a unique interline space. These are computed by overriding the
70 MultiRowTextImager::CalculateInterLineSpace () method. They are not set directly.
71 </p>
72 */
73 inline DistanceType MultiRowTextImager::PartitionElementCacheInfo::GetInterLineSpace () const
74 {
75 Assert (fRep->fInterlineSpace != DistanceType (-1));
76 return (fRep->fInterlineSpace);
77 }
78 inline void MultiRowTextImager::PartitionElementCacheInfo::SetInterLineSpace (DistanceType interlineSpace)
79 {
80 Assert (interlineSpace != DistanceType (-1));
81 fRep->fInterlineSpace = interlineSpace;
82 }
83 /*
84 @METHOD: MultiRowTextImager::PartitionElementCacheInfo::GetPixelHeight
85 @DESCRIPTION: <p>Return the cached height of the given partition element. This is the sum of the
86 pixel height computed in FillCache () for the actual text, and the interline space (see GetInterLineSpace ()).</p>
87 */
88 inline DistanceType MultiRowTextImager::PartitionElementCacheInfo::GetPixelHeight () const
89 {
90 return (fRep->fPixelHeightCache + GetInterLineSpace ());
91 }
92 /*
93 @METHOD: MultiRowTextImager::PartitionElementCacheInfo::GetRowCount
94 @DESCRIPTION: <p>Return the cached number of rows in this partition element. This is computed in
95 MultiRowTextImager::FillCache (), and specified indirectly via calls (from inside FillCache)
96 to MultiRowTextImager::MultiRowPartitionMarker::IncrementRowCountAndFixCacheBuffers ().</p>
97 */
98 inline size_t MultiRowTextImager::PartitionElementCacheInfo::GetRowCount () const
99 {
100 Assert (fRep->fRowCountCache >= 1); // even for empty lines we have 1 row (by definition)
101 return (fRep->fRowCountCache);
102 }
103 /*
104 @METHOD: MultiRowTextImager::PartitionElementCacheInfo::PeekRowCount
105 @DESCRIPTION: <p>Return the cached number of rows in this partition element. This is computed in
106 MultiRowTextImager::FillCache (), and specified indirectly via calls (from inside FillCache)
107 to MultiRowTextImager::MultiRowPartitionMarker::IncrementRowCountAndFixCacheBuffers ().</p>
108 */
109 inline size_t MultiRowTextImager::PartitionElementCacheInfo::PeekRowCount () const
110 {
111 return (fRep->fRowCountCache);
112 }
113 /*
114 @METHOD: MultiRowTextImager::PartitionElementCacheInfo::GetLastRow
115 @DESCRIPTION: <p>Return the last valid row index (may invoke FillCache if cached result not
116 already available).</p>
117 */
118 inline size_t MultiRowTextImager::PartitionElementCacheInfo::GetLastRow () const
119 {
120 return GetRowCount () - 1;
121 }
122 /*
123 @METHOD: MultiRowTextImager::PartitionElementCacheInfo::PeekAtRowHeight
124 @DESCRIPTION: <p>Return the height - (in whatever unit the GDI is using, but typically pixels) of the given row.
125 The internal representation of these things is somewhat obscure for data size reasons, so there is some
126 unpacking to be done.</p>
127 */
128 inline DistanceType MultiRowTextImager::PartitionElementCacheInfo::PeekAtRowHeight (size_t i) const
129 {
130 Assert (i < fRep->fRowCountCache); // MFC Hint - when this assert fails, look closely at your
131 // stack-trace - often its cuz some other assert failed in the context
132 // of a FillCache, and so the cache info isn't completely filled in
133 // yet...
134 /*
135 * A bit of trickery. --- XPLAIN
136 */
137 if (fRep->fRowCountCache <= kPackRowHeightCount) {
138 // Then we use the pointer to the array as the actual array
139 const RowHeight_* theArray = reinterpret_cast<const RowHeight_*> (&fRep->fRowHeightArray);
140 return (theArray[i]);
141 }
142 AssertNotNull (fRep->fRowHeightArray);
143 return (fRep->fRowHeightArray[i]);
144 }
145 /*
146 @METHOD: MultiRowTextImager::PartitionElementCacheInfo::SetRowHeight
147 @DESCRIPTION: <p>Set the height of a given row. This is typically just done within FillCache().</p>
148 */
149 inline void MultiRowTextImager::PartitionElementCacheInfo::SetRowHeight (size_t i, DistanceType rowHeight)
150 {
151 Assert (i < fRep->fRowCountCache);
152 Assert (sizeof (RowHeight_) > 1 or rowHeight <= 0xff); // be sure value fits..
153 Assert (sizeof (RowHeight_) > 2 or rowHeight <= 0xffff); // be sure value fits.
154 /*
155 * A bit of trickery. --- XPLAIN
156 */
157 if (fRep->fRowCountCache <= kPackRowHeightCount) {
158 // Then we use the pointer to the array as the actual array
159 RowHeight_* theArray = reinterpret_cast<RowHeight_*> (&fRep->fRowHeightArray);
160 theArray[i] = RowHeight_ (rowHeight);
161 }
162 else {
163 AssertNotNull (fRep->fRowHeightArray);
164 fRep->fRowHeightArray[i] = RowHeight_ (rowHeight);
165 }
166 }
167 /*
168 @METHOD: MultiRowTextImager::PartitionElementCacheInfo::PeekAtRowStart
169 @DESCRIPTION: <p>Return the partition element relative offset of the start of a given row. So for the
170 first row, this is always zero.</p>
171 */
172 inline size_t MultiRowTextImager::PartitionElementCacheInfo::PeekAtRowStart (size_t i) const
173 {
174 Assert (i < fRep->fRowCountCache);
175
176 if (i == 0) {
177 return (0);
178 }
179 else {
180 /*
181 * A bit of trickery. --- XPLAIN
182 */
183 Assert (i >= 1);
184 if (fRep->fRowCountCache <= kPackRowStartCount + 1) {
185 // Then we use the pointer to the array as the actual array
186 const RowStart_* theArray = reinterpret_cast<const RowStart_*> (&fRep->fRowStartArray);
187 return (theArray[i - 1]);
188 }
189 AssertNotNull (fRep->fRowStartArray);
190 return (fRep->fRowStartArray[i - 1]);
191 }
192 }
193 /*
194 @METHOD: MultiRowTextImager::PartitionElementCacheInfo::SetRowStart
195 @DESCRIPTION: <p>Set the partition element relative offset of the start of a given row. So for the
196 first row, this is MUST BE zero. This is typically just called during FillCache ().</p>
197 */
198 inline void MultiRowTextImager::PartitionElementCacheInfo::SetRowStart (size_t i, size_t rowStart)
199 {
200 Assert (i < fRep->fRowCountCache);
201
202 if (i == 0) {
203 Assert (rowStart == 0);
204 }
205 else {
206 /*
207 * A bit of trickery. --- XPLAIN
208 */
209 Assert (i >= 1);
210 Assert (sizeof (RowStart_) > 1 or rowStart <= 0xff); // be sure value fits..
211 Assert (sizeof (RowStart_) > 2 or rowStart <= 0xffff); // be sure value fits.
212 if (fRep->fRowCountCache <= kPackRowStartCount + 1) {
213 // Then we use the pointer to the array as the actual array
214 RowStart_* theArray = reinterpret_cast<RowStart_*> (&fRep->fRowStartArray);
215 theArray[i - 1] = RowStart_ (rowStart);
216 }
217 else {
218 AssertNotNull (fRep->fRowStartArray);
219 fRep->fRowStartArray[i - 1] = RowStart_ (rowStart);
220 }
221 }
222 }
223 inline size_t MultiRowTextImager::PartitionElementCacheInfo::GetLineRelativeRowStartPosition (size_t ithRow) const
224 {
225 return (PeekAtRowStart (ithRow));
226 }
227 inline DistanceType MultiRowTextImager::PartitionElementCacheInfo::GetRowHeight (size_t ithRow) const
228 {
229 return (PeekAtRowHeight (ithRow));
230 }
231 inline size_t MultiRowTextImager::PartitionElementCacheInfo::LineRelativePositionInWhichRow (size_t charPos) const
232 {
233 // ZERO based charPos - ie zero is just before first byte in first row
234 // Require (charPos >= 0); // yes I know this is a degenerate test - just for doc purposes...
235 // Assert (charPos < OURLENGTH);
236 for (size_t row = fRep->fRowCountCache; row >= 1; --row) {
237 if (charPos >= PeekAtRowStart (row - 1)) {
238 return row - 1;
239 }
240 }
241 Assert (false);
242 return 0; // if we get here - must have been before our line...
243 }
244
245 /*
246 ********************************************************************************
247 ************************ MultiRowTextImager::RowReference **********************
248 ********************************************************************************
249 */
250 inline MultiRowTextImager::RowReference::RowReference (PartitionMarker* partitionMarker, size_t subRow)
251 : fPartitionMarker (partitionMarker)
252 , fSubRow (subRow)
253 {
254 }
255 inline MultiRowTextImager::RowReference& MultiRowTextImager::RowReference::operator= (const MultiRowTextImager::RowReference& rhs)
256 {
257 fPartitionMarker = rhs.fPartitionMarker;
258 fSubRow = rhs.fSubRow;
259 return (*this);
260 }
261 inline MultiRowTextImager::PartitionMarker* MultiRowTextImager::RowReference::GetPartitionMarker () const
262 {
263 return (fPartitionMarker);
264 }
265 inline size_t MultiRowTextImager::RowReference::GetSubRow () const
266 {
267 return (fSubRow);
268 }
269 inline bool MultiRowTextImager::RowReference::operator== (MultiRowTextImager::RowReference rhs) const
270 {
271 return this->GetPartitionMarker () == rhs.GetPartitionMarker () and this->GetSubRow () == rhs.GetSubRow ();
272 }
273
274 /*
275 ********************************************************************************
276 ********************************* MultiRowTextImager ***************************
277 ********************************************************************************
278 */
279 /*
280 @METHOD: MultiRowTextImager::GetNextRowReference
281 @DESCRIPTION: <p>Advance the given row reference argument to the next row. Return true if there
282 is a valid next row. And false if <code>adjustMeInPlace</code> was already on the last row.</p>
283 <p>See also @'MultiRowTextImager::GetPreviousRowReference'.</p>
284 */
285 inline bool MultiRowTextImager::GetNextRowReference (RowReference* adjustMeInPlace) const
286 {
287 RequireNotNull (adjustMeInPlace);
288 PartitionMarker* cur = adjustMeInPlace->GetPartitionMarker ();
289 size_t subRow = adjustMeInPlace->GetSubRow ();
290 PartitionElementCacheInfo pmCacheInfo = GetPartitionElementCacheInfo (cur);
291 if (subRow + 1 < pmCacheInfo.GetRowCount ()) {
292 ++subRow;
293 *adjustMeInPlace = RowReference{cur, subRow};
294 return true;
295 }
296 else {
297 if (cur->GetNext () == nullptr) {
298 return false;
299 }
300 else {
301 cur = cur->GetNext ();
302 subRow = 0;
303 *adjustMeInPlace = RowReference{cur, subRow};
304 return true;
305 }
306 }
307 }
308 /*
309 @METHOD: MultiRowTextImager::GetPreviousRowReference
310 @DESCRIPTION: <p>Retreat the given row reference argument to the previous row. Return true if there
311 is a valid previous row. And false if <code>adjustMeInPlace</code> was already on the first row.</p>
312 <p>See also @'MultiRowTextImager::GetNextRowReference'.</p>
313 */
314 inline bool MultiRowTextImager::GetPreviousRowReference (RowReference* adjustMeInPlace) const
315 {
316 AssertNotNull (adjustMeInPlace);
317 PartitionMarker* cur = adjustMeInPlace->GetPartitionMarker ();
318 size_t subRow = adjustMeInPlace->GetSubRow ();
319 if (subRow > 0) {
320 --subRow;
321 *adjustMeInPlace = RowReference{cur, subRow};
322 return true;
323 }
324 else {
325 if (cur->GetPrevious () == nullptr) {
326 return false;
327 }
328 else {
329 cur = cur->GetPrevious ();
330 PartitionElementCacheInfo pmCacheInfo = GetPartitionElementCacheInfo (cur);
331 subRow = pmCacheInfo.GetRowCount () - 1;
332 *adjustMeInPlace = RowReference{cur, subRow};
333 return true;
334 }
335 }
336 }
337 /*
338 @METHOD: MultiRowTextImager::GetIthRowReferenceFromHere
339 @DESCRIPTION: <p>Adjust <code>fromHere</code> by <code>ith</code> rows. If <code>ith</code> is zero, then
340 this returns <code>fromHere</code>. It asserts there are at least ith rows from the given one to retrieve.
341 It calls @'MultiRowTextImager::GetIthRowReferenceFromHere' todo its work (which returns a bool rather than asserting).</p>
342 <p>See also @'MultiRowTextImager::GetNextRowReference', @'MultiRowTextImager::GetPreviousRowReference'.</p>
343 */
344 inline MultiRowTextImager::RowReference MultiRowTextImager::GetIthRowReferenceFromHere (RowReference fromHere, ptrdiff_t ith) const
345 {
346 [[maybe_unused]] bool result = GetIthRowReferenceFromHere (&fromHere, ith);
347 Assert (result);
348 return fromHere;
349 }
350 /*
351 @METHOD: MultiRowTextImager::GetIthRowReference
352 @DESCRIPTION: <p>Get the <code>ith</code> row reference in the document. Asserts value <code>ith</code> refers to
353 a valid row number.</p>
354 <p>It calls @'MultiRowTextImager::GetIthRowReferenceFromHere' todo its work (which returns a bool rather than asserting).</p>
355 */
356 inline MultiRowTextImager::RowReference MultiRowTextImager::GetIthRowReference (size_t ith) const
357 {
358 RowReference fromHere (GetFirstPartitionMarker (), 0);
359 [[maybe_unused]] bool result = GetIthRowReferenceFromHere (&fromHere, ith);
360 Assert (result);
361 return fromHere;
362 }
363 /*
364 @METHOD: MultiRowTextImager::GetRowLength
365 @DESCRIPTION: <p>Gets the length of the given row (in @'Led_tChar's).</p>
366 <p>See also @'MultiRowTextImager::GetStartOfRow' and @'MultiRowTextImager::GetEndOfRow'.</p>
367 */
368 inline size_t MultiRowTextImager::GetRowLength (RowReference row) const
369 {
370 return (GetEndOfRow (row) - GetStartOfRow (row));
371 }
372 /*
373 @METHOD: MultiRowTextImager::GetLastRowReferenceInWindow
374 @DESCRIPTION: <p>Returns the last row-reference in the window (end of window).</p>
375 */
376 inline MultiRowTextImager::RowReference MultiRowTextImager::GetLastRowReferenceInWindow () const
377 {
378 RowReference row = GetTopRowReferenceInWindow ();
379 Assert (GetTotalRowsInWindow_ () >= 1);
380 (void)GetIthRowReferenceFromHere (&row, GetTotalRowsInWindow_ () - 1);
381 return (row);
382 }
383 inline void MultiRowTextImager::SetTopRowInWindow_ (RowReference row)
384 {
385 fTopLinePartitionMarkerInWindow = row.GetPartitionMarker ();
386 fSubRowInTopLineInWindow = row.GetSubRow ();
387 AssertNotNull (fTopLinePartitionMarkerInWindow);
388 InvalidateTotalRowsInWindow ();
389 }
390 /*
391 @METHOD: MultiRowTextImager::GetRowHeight
392 @DESCRIPTION: <p>Returns the height (in standard GDI units, usually pixels) of the given row reference.</p>
393 */
394 inline DistanceType MultiRowTextImager::GetRowHeight (RowReference row) const
395 {
396 AssertNotNull (row.GetPartitionMarker ());
397 return GetPartitionElementCacheInfo (row.GetPartitionMarker ()).GetRowHeight (row.GetSubRow ());
398 }
399#endif
400
401}
#define AssertNotNull(p)
Definition Assertions.h:333
#define EnsureNotNull(p)
Definition Assertions.h:340
#define RequireNotNull(p)
Definition Assertions.h:347