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