NXWidgets: ctext.cxx Source File

NXWidgets 1.19

ctext.cxx
Go to the documentation of this file.
1 /****************************************************************************
2 * NxWidgets/libnxwidgets/src/ctext.cxx
3 *
4 * Copyright (C) 2012, 2016 Gregory Nutt. All rights reserved.
5 * Author: Gregory Nutt <gnutt@nuttx.org>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name NuttX, NxWidgets, nor the names of its contributors
18 * me be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *
34 ****************************************************************************
35 *
36 * Portions of this package derive from Woopsi (http://woopsi.org/) and
37 * portions are original efforts. It is difficult to determine at this
38 * point what parts are original efforts and which parts derive from Woopsi.
39 * However, in any event, the work of Antony Dzeryn will be acknowledged
40 * in most NxWidget files. Thanks Antony!
41 *
42 * Copyright (c) 2007-2011, Antony Dzeryn
43 * All rights reserved.
44 *
45 * Redistribution and use in source and binary forms, with or without
46 * modification, are permitted provided that the following conditions are met:
47 *
48 * * Redistributions of source code must retain the above copyright
49 * notice, this list of conditions and the following disclaimer.
50 * * Redistributions in binary form must reproduce the above copyright
51 * notice, this list of conditions and the following disclaimer in the
52 * documentation and/or other materials provided with the distribution.
53 * * Neither the names "Woopsi", "Simian Zombie" nor the
54 * names of its contributors may be used to endorse or promote products
55 * derived from this software without specific prior written permission.
56 *
57 * THIS SOFTWARE IS PROVIDED BY Antony Dzeryn ``AS IS'' AND ANY
58 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
59 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
60 * DISCLAIMED. IN NO EVENT SHALL Antony Dzeryn BE LIABLE FOR ANY
61 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
62 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
63 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
64 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
65 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
66 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
67 *
68 ****************************************************************************/
69
70 /****************************************************************************
71 * Included Files
72 ****************************************************************************/
73
74 #include <nuttx/config.h>
75
76 #include <stdint.h>
77 #include <stdbool.h>
78
79 #include "ctext.hxx"
80 #include "cstringiterator.hxx"
81
82 /****************************************************************************
83 * Pre-Processor Definitions
84 ****************************************************************************/
85
86 /****************************************************************************
87 * Method Implementations
88 ****************************************************************************/
89
90 using namespace NXWidgets;
91
92 /**
93 * Constructor.
94 *
95 * @param font The font to use for this text object.
96 * @param text A string that this text object should wrap around.
97 * @param width The pixel width at which the text should wrap.
98 */
99
100 CText::CText(CNxFont *font, const CNxString &text, nxgl_coord_t width)
101 : CNxString(text)
102 {
103 m_font = font;
104 m_width = width;
105 m_lineSpacing = 1;
106 wrap();
107 }
108
109 /**
110 * Set the text in the string.
111 *
112 * @param text Char array to use as the new data for this string.
113 */
114
115 void CText::setText(const CNxString &text)
116 {
117 CNxString::setText(text);
118 wrap();
119 }
120
121 /**
122 * Set the text in the string.
123 *
124 * @param text Char array to use as the new data for this string.
125 */
126
127 void CText::setText(FAR const char *text)
128 {
129 CNxString::setText(text);
130 wrap();
131 }
132
133 /**
134 * Set the text in the string.
135 *
136 * @param text Character to to use as the new data for this string.
137 */
138
139 void CText::setText(const nxwidget_char_t text)
140 {
141 CNxString::setText(text);
142 wrap();
143 }
144
145 /**
146 * Append text to the end of the string.
147 *
148 * @param text String to append.
149 */
150
151 void CText::append(const CNxString &text)
152 {
153 CNxString::append(text);
154 wrap(getLength() - 1);
155 }
156
157 /**
158 * Insert text at the specified character index.
159 *
160 * @param text The text to insert.
161 * @param index The char index to insert at.
162 */
163
164 void CText::insert(const CNxString &text, const int index)
165 {
166 CNxString::insert(text, index);
167 wrap(index);
168 }
169
170 /**
171 * Remove all characters from the string from the start index onwards.
172 *
173 * @param startIndex The char index to start removing from.
174 */
175
176 void CText::remove(const int startIndex)
177 {
178 CNxString::remove(startIndex);
179 wrap(startIndex);
180 }
181
182 /**
183 * Remove all characters from the string from the start index onwards.
184 *
185 * @param startIndex The char index to start removing from.
186 * @param count The number of chars to remove.
187 */
188
189 void CText::remove(const int startIndex, const int count)
190 {
191 CNxString::remove(startIndex, count);
192 wrap(startIndex);
193 }
194
195
196 /**
197 * Set the vertical spacing between rows of text.
198 *
199 * @param lineSpacing The line spacing.
200 */
201
202 void CText::setLineSpacing(nxgl_coord_t lineSpacing)
203 {
204 m_lineSpacing = lineSpacing;
205 wrap();
206 }
207
208 /**
209 * Sets the pixel width of the text; text wider than
210 * this will automatically wrap.
211 *
212 * @param width Maximum pixel width of the text.
213 */
214
215 void CText::setWidth(nxgl_coord_t width)
216 {
217 m_width = width;
218 wrap();
219 }
220
221 /**
222 * Set the font to use.
223 *
224 * @param font Pointer to the new font.
225 */
226
227 void CText::setFont(CNxFont* font)
228 {
229 m_font = font;
230 wrap();
231 }
232
233 /**
234 * Get the number of characters in the specified line number.
235 *
236 * @param lineNumber The line number to check.
237 * @return The number of characters in the line.
238 */
239
240 const int CText::getLineLength(const int lineNumber) const
241 {
242 if (lineNumber < getLineCount() - 1)
243 {
244 return m_linePositions[lineNumber + 1] - m_linePositions[lineNumber];
245 }
246
247 return getLength() - m_linePositions[lineNumber];
248 }
249
250 /**
251 * Get the number of characters in the specified line number,
252 * ignoring any trailing blank characters.
253 *
254 * @param lineNumber The line number to check.
255 * @return The number of characters in the line.
256 */
257
258 const int CText::getLineTrimmedLength(const int lineNumber) const
259 {
260 nxgl_coord_t length = getLineLength(lineNumber);
261
262 // Loop through string until the end
263
264 CStringIterator *iterator = newStringIterator();
265
266 // Get char at the end of the line
267
268 if (iterator->moveTo(m_linePositions[lineNumber] + length - 1))
269 {
270 do
271 {
272 if (!m_font->isCharBlank(iterator->getChar()))
273 {
274 break;
275 }
276 length--;
277 }
278 while (iterator->moveToPrevious() && (length > 0));
279
280 delete iterator;
281 return length;
282 }
283
284 // May occur if data has been horribly corrupted somewhere
285
286 delete iterator;
287 return 0;
288 }
289
290 /**
291 * Get the width in pixels of the specified line number.
292 *
293 * @param lineNumber The line number to check.
294 * @return The pixel width of the line.
295 */
296
297 const nxgl_coord_t CText::getLinePixelLength(const int lineNumber) const
298 {
299 return m_font->getStringWidth(*this, getLineStartIndex(lineNumber),
300 getLineLength(lineNumber));
301 }
302
303 /**
304 * Get the width in pixels of the specified line number,
305 * ignoring any trailing blank characters.
306 *
307 * @param lineNumber The line number to check.
308 * @return The pixel width of the line.
309 */
310
311 const nxgl_coord_t CText::getLineTrimmedPixelLength(const int lineNumber) const
312 {
313 return m_font->getStringWidth(*this, getLineStartIndex(lineNumber),
314 getLineTrimmedLength(lineNumber));
315 }
316
317 /**
318 * Get a pointer to the CText object's font.
319 *
320 * @return Pointer to the font.
321 */
322
323 CNxFont *CText::getFont(void) const
324 {
325 return m_font;
326 }
327
328 /**
329 * Removes lines of text from the start of the text buffer.
330 *
331 * @param lines Number of lines to remove
332 */
333
334 void CText::stripTopLines(const int lines)
335 {
336 // Get the start point of the text we want to keep
337
338 nxgl_coord_t textStart = 0;
339
340 for (int i = 0; i < lines; i++)
341 {
342 textStart += getLineLength(i);
343 }
344
345 // Remove the characters from the start of the string to the found location
346
347 remove(0, textStart);
348
349 // Rewrap the text
350
351 wrap();
352 }
353
354 /**
355 * Wrap all of the text.
356 */
357
358 void CText::wrap(void)
359 {
360 wrap(0);
361 }
362
363 /**
364 * Wrap the text from the line containing the specified char index onwards.
365 *
366 * @param charIndex The index of the char to start wrapping from; note
367 * that the wrapping function will re-wrap that entire line of text.
368 */
369
370 void CText::wrap(int charIndex)
371 {
372 // Declare vars in advance of loop
373
374 int pos = 0;
375 int lineWidth;
376 int breakIndex;
377 bool endReached = false;
378
379 if (m_linePositions.size() == 0)
380 {
381 charIndex = 0;
382 }
383
384 // If we're wrapping from an offset in the text, ensure that any existing data
385 // after the offset gets removed
386
387 if (charIndex > 0)
388 {
389 // Remove wrapping data past this point
390
391 // Get the index of the line in which the char index appears
392
393 int lineIndex = getLineContainingCharIndex(charIndex);
394
395 // Remove any longest line records that occur from the line index onwards
396
397 while ((m_longestLines.size() > 0) &&
398 (m_longestLines[m_longestLines.size() - 1].index >= lineIndex))
399 {
400 m_longestLines.pop_back();
401 }
402
403 // If there are any longest line records remaining, update the text pixel width
404 // The last longest line record will always be the last valid longest line as
405 // the vector is sorted by length
406
407 if (m_longestLines.size() > 0)
408 {
409 m_textPixelWidth = m_longestLines[m_longestLines.size() - 1].width;
410 }
411 else
412 {
413 m_textPixelWidth = 0;
414 }
415
416 // Remove any wrapping data from after this line index onwards
417
418 while ((m_linePositions.size() > 0) &&
419 (m_linePositions.size() - 1 > (int)lineIndex))
420 {
421 m_linePositions.pop_back();
422 }
423
424 // Adjust start position of wrapping loop so that it starts with
425 // the current line index
426
427 if (m_linePositions.size() > 0)
428 {
429 pos = m_linePositions[m_linePositions.size() - 1];
430 }
431 }
432 else
433 {
434 // Remove all wrapping data
435
436 // Wipe the width variable
437
438 m_textPixelWidth = 0;
439
440 // Empty existing longest lines
441
442 m_longestLines.clear();
443
444 // Empty existing line positions
445
446 m_linePositions.clear();
447
448 // Push first line start into vector
449
450 m_linePositions.push_back(0);
451 }
452
453 // Loop through string until the end
454
455 CStringIterator *iterator = newStringIterator();
456
457 while (!endReached)
458 {
459 breakIndex = 0;
460 lineWidth = 0;
461
462 if (iterator->moveTo(pos))
463 {
464 // Search for line breaks and valid breakpoints until we
465 // exceed the width of the text field or we run out of
466 // string to process
467
468 while (lineWidth + m_font->getCharWidth(iterator->getChar()) <= m_width)
469 {
470 lineWidth += m_font->getCharWidth(iterator->getChar());
471
472 // Check for line return
473
474 if (iterator->getChar() == '\n')
475 {
476 // Remember this breakpoint
477
478 breakIndex = iterator->getIndex();
479 break;
480 }
481 else if ((iterator->getChar() == ' ') ||
482 (iterator->getChar() == ',') ||
483 (iterator->getChar() == '.') ||
484 (iterator->getChar() == '-') ||
485 (iterator->getChar() == ':') ||
486 (iterator->getChar() == ';') ||
487 (iterator->getChar() == '?') ||
488 (iterator->getChar() == '!') ||
489 (iterator->getChar() == '+') ||
490 (iterator->getChar() == '=') ||
491 (iterator->getChar() == '/') ||
492 (iterator->getChar() == '\0'))
493 {
494 // Remember the most recent breakpoint
495
496 breakIndex = iterator->getIndex();
497 }
498
499 // Move to the next character
500
501 if (!iterator->moveToNext())
502 {
503 // No more text; abort loop
504
505 endReached = true;
506 break;
507 }
508 }
509 }
510 else
511 {
512 endReached = true;
513 }
514
515 if ((!endReached) && (iterator->getIndex() > pos))
516 {
517 // Process any found data
518
519 // If we didn't find a breakpoint split at the current position
520
521 if (breakIndex == 0)
522 {
523 breakIndex = iterator->getIndex() - 1;
524 }
525
526 // Trim blank space from the start of the next line
527
528 CStringIterator *breakIterator = newStringIterator();
529
530 if (breakIterator->moveTo(breakIndex + 1))
531 {
532 while (breakIterator->getChar() == ' ')
533 {
534 if (breakIterator->moveToNext())
535 {
536 breakIndex++;
537 }
538 else
539 {
540 break;
541 }
542 }
543 }
544
545 delete breakIterator;
546
547 // Add the start of the next line to the vector
548
549 pos = breakIndex + 1;
550 m_linePositions.push_back(pos);
551
552 // Is this the longest line observed so far?
553
554 if (lineWidth > m_textPixelWidth)
555 {
556 m_textPixelWidth = lineWidth;
557
558 // Push the description of the line into the longest lines
559 // vector (note that we store the index in m_linePositions that
560 // refers to the start of the line, *not* the position of the
561 // line in the char array)
562
563 LongestLine line;
564 line.index = m_linePositions.size() - 2;
565 line.width = lineWidth;
566 m_longestLines.push_back(line);
567 }
568 }
569 else if (!endReached)
570 {
571 // Add a blank row if we're not at the end of the string
572
573 pos++;
574 m_linePositions.push_back(pos);
575 }
576 }
577
578 // Add marker indicating end of text
579 // If we reached the end of the text, append the stopping point
580
581 if (m_linePositions[m_linePositions.size() - 1] != getLength() + 1)
582 {
583 m_linePositions.push_back(getLength());
584 }
585
586 delete iterator;
587
588 // Calculate the total height of the text
589
590 m_textPixelHeight = getLineCount() * (m_font->getHeight() + m_lineSpacing);
591
592 // Ensure height is always at least one row
593
594 if (m_textPixelHeight == 0)
595 {
596 m_textPixelHeight = m_font->getHeight() + m_lineSpacing;
597 }
598 }
599
600 /**
601 * Get the index of the line of text that contains the specified index
602 * within the raw char array.
603 *
604 * @param index The index to locate within the wrapped lines of text.
605 * @return The number of the line of wrapped text that contains the
606 * specified index.
607 */
608
609 const int CText::getLineContainingCharIndex(const int index) const
610 {
611 // Early exit if there is no existing line data
612
613 if (m_linePositions.size() == 0)
614 {
615 return 0;
616 }
617
618 // Early exit if the character is in the last row
619
620 if (index >= m_linePositions[m_linePositions.size() - 2])
621 {
622 return m_linePositions.size() - 2;
623 }
624
625 // Binary search the line vector for the line containing the supplied index
626
627 int bottom = 0;
628 int top = m_linePositions.size() - 1;
629 int mid;
630
631 while (bottom <= top)
632 {
633 // Standard binary search
634
635 mid = (bottom + top) >> 1;
636
637 if (index < m_linePositions[mid])
638 {
639 // Index is somewhere in the lower search space
640
641 top = mid - 1;
642 }
643 else if (index > m_linePositions[mid])
644 {
645 // Index is somewhere in the upper search space
646
647 bottom = mid + 1;
648 }
649 else if (index == m_linePositions[mid])
650 {
651 // Located the index
652
653 return mid;
654 }
655
656 // Check to see if we've moved past the line that contains the index
657 // We have to do this because the index we're looking for can be within
658 // a line; it isn't necessarily the start of a line (which is what is
659 // stored in the m_linePositions vector)
660
661 if (index > m_linePositions[top])
662 {
663 // Search index falls within the line represented by the top position
664
665 return top;
666 }
667 else if (index < m_linePositions[bottom])
668 {
669 // Search index falls within the line represented by the bottom position
670
671 return bottom - 1;
672 }
673 }
674
675 // Line cannot be found
676
677 return 0;
678 }
NXWidgets::CText::getLineContainingCharIndex
const int getLineContainingCharIndex(const int index) const
Definition: ctext.cxx:609
NXWidgets::CStringIterator
Definition: cstringiterator.hxx:102
NXWidgets::CStringIterator::getIndex
int getIndex(void) const
Definition: cstringiterator.hxx:172
NXWidgets::CNxFont::getCharWidth
nxgl_coord_t getCharWidth(nxwidget_char_t letter) const
Definition: cnxfont.cxx:254
NXWidgets::CText::getLineLength
const int getLineLength(const int lineNumber) const
Definition: ctext.cxx:240
NXWidgets::CText::m_lineSpacing
nxgl_coord_t m_lineSpacing
Definition: ctext.hxx:129
NXWidgets::CText::stripTopLines
void stripTopLines(const int lines)
Definition: ctext.cxx:334
NXWidgets::CText::m_linePositions
TNxArray< int > m_linePositions
Definition: ctext.hxx:124
NXWidgets::CText::getLineTrimmedLength
const int getLineTrimmedLength(const int lineNumber) const
Definition: ctext.cxx:258
NXWidgets::CStringIterator::moveToPrevious
bool moveToPrevious(void)
Definition: cstringiterator.cxx:167
NXWidgets::CText::m_font
CNxFont * m_font
Definition: ctext.hxx:123
NXWidgets::CText::setText
virtual void setText(const CNxString &text)
Definition: ctext.cxx:115
NXWidgets::CNxString::append
void append(const CNxString &text)
Definition: cnxstring.cxx:267
TNxArray::pop_back
void pop_back(void)
Definition: tnxarray.hxx:283
NXWidgets::CText::getLineTrimmedPixelLength
const nxgl_coord_t getLineTrimmedPixelLength(const int lineNumber) const
Definition: ctext.cxx:311
cstringiterator.hxx
NXWidgets::CNxFont::getStringWidth
nxgl_coord_t getStringWidth(const CNxString &text) const
Definition: cnxfont.cxx:142
NXWidgets::CText::append
virtual void append(const CNxString &text)
Definition: ctext.cxx:151
NXWidgets
Definition: cbgwindow.hxx:65
NXWidgets::CNxString::remove
void remove(const int startIndex)
Definition: cnxstring.cxx:398
NXWidgets::CText::m_textPixelHeight
int32_t m_textPixelHeight
Definition: ctext.hxx:130
NXWidgets::CText::LongestLine::width
uint8_t width
Definition: ctext.hxx:120
NXWidgets::CText::getLinePixelLength
const nxgl_coord_t getLinePixelLength(const int lineNumber) const
Definition: ctext.cxx:297
ctext.hxx
NXWidgets::CText::CText
CText(CNxFont *font, const CNxString &text, nxgl_coord_t width)
Definition: ctext.cxx:100
NXWidgets::CStringIterator::moveToNext
bool moveToNext(void)
Definition: cstringiterator.cxx:149
NXWidgets::nxwidget_char_t
uint16_t nxwidget_char_t
Definition: nxconfig.hxx:454
NXWidgets::CNxFont
Definition: cnxfont.hxx:70
NXWidgets::CText::getLineStartIndex
const int getLineStartIndex(const int line) const
Definition: ctext.hxx:382
NXWidgets::CStringIterator::getChar
nxwidget_char_t getChar(void) const
Definition: cstringiterator.hxx:183
NXWidgets::CText::m_width
nxgl_coord_t m_width
Definition: ctext.hxx:134
TNxArray::clear
void clear()
Definition: tnxarray.hxx:428
NXWidgets::CNxString::setText
void setText(const CNxString &text)
Definition: cnxstring.cxx:185
NXWidgets::CText::insert
virtual void insert(const CNxString &text, const int index)
Definition: ctext.cxx:164
NXWidgets::CText::m_textPixelWidth
uint8_t m_textPixelWidth
Definition: ctext.hxx:132
NXWidgets::CText::getFont
CNxFont * getFont(void) const
Definition: ctext.cxx:323
NXWidgets::CText::wrap
void wrap(void)
Definition: ctext.cxx:358
TNxArray::push_back
void push_back(const T &value)
Definition: tnxarray.hxx:267
NXWidgets::CText::setFont
void setFont(CNxFont *font)
Definition: ctext.cxx:227
NXWidgets::CNxFont::getHeight
const uint8_t getHeight(void) const
Definition: cnxfont.hxx:229
NXWidgets::CText::LongestLine::index
int index
Definition: ctext.hxx:119
NXWidgets::CNxString::getLength
const unsigned int getLength(void) const
Definition: cnxstring.hxx:325
NXWidgets::CNxFont::isCharBlank
const bool isCharBlank(const nxwidget_char_t letter) const
Definition: cnxfont.cxx:93
NXWidgets::CText::setWidth
void setWidth(nxgl_coord_t width)
Definition: ctext.cxx:215
NXWidgets::CNxString::newStringIterator
CStringIterator * newStringIterator(void) const
Definition: cnxstring.cxx:156
NXWidgets::CNxString
Definition: cnxstring.hxx:121
NXWidgets::CText::m_longestLines
TNxArray< LongestLine > m_longestLines
Definition: ctext.hxx:126
NXWidgets::CText::getLineCount
const int getLineCount(void) const
Definition: ctext.hxx:327
NXWidgets::CNxString::insert
void insert(const CNxString &text, const int index)
Definition: cnxstring.cxx:295
NXWidgets::CStringIterator::moveTo
bool moveTo(int index)
Definition: cstringiterator.cxx:185
TNxArray::size
const int size(void) const
Definition: tnxarray.hxx:261
NXWidgets::CText::remove
virtual void remove(const int startIndex)
Definition: ctext.cxx:176
NXWidgets::CText::setLineSpacing
void setLineSpacing(nxgl_coord_t lineSpacing)
Definition: ctext.cxx:202
NXWidgets::CText::LongestLine
Definition: ctext.hxx:117