0030537: Visualization - wrapping text in font text formatter
[occt.git] / src / Font / Font_TextFormatter.hxx
CommitLineData
a174a3c5 1// Created on: 2013-01-29
2// Created by: Kirill GAVRILOV
d5f74e42 3// Copyright (c) 2013-2014 OPEN CASCADE SAS
a174a3c5 4//
973c2be1 5// This file is part of Open CASCADE Technology software library.
a174a3c5 6//
d5f74e42 7// This library is free software; you can redistribute it and/or modify it under
8// the terms of the GNU Lesser General Public License version 2.1 as published
973c2be1 9// by the Free Software Foundation, with special exception defined in the file
10// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11// distribution for complete text of the license and disclaimer of any warranty.
a174a3c5 12//
973c2be1 13// Alternatively, this file may be used under the terms of Open CASCADE
14// commercial license or contractual agreement.
a174a3c5 15
317d68c9 16#ifndef Font_TextFormatter_Header
17#define Font_TextFormatter_Header
a174a3c5 18
d2eddacc 19#include <Font_Rect.hxx>
20#include <Graphic3d_HorizontalTextAlignment.hxx>
21#include <Graphic3d_VerticalTextAlignment.hxx>
317d68c9 22#include <NCollection_DataMap.hxx>
23#include <NCollection_Vector.hxx>
d2eddacc 24#include <NCollection_String.hxx>
25
26class Font_FTFont;
a174a3c5 27
60f7b225 28DEFINE_STANDARD_HANDLE(Font_TextFormatter, Standard_Transient)
29
30//! This class is intended to prepare formatted text by using:<br>
31//! - font to string combination,<br>
32//! - alignment,<br>
33//! - wrapping.<br>
34//!
35//! After text formatting, each symbol of formatted text is placed in some position.
36//! Further work with the formatter is using an iterator.
37//! The iterator gives an access to each symbol inside the initial row.
38//! Also it's possible to get only significant/writable symbols of the text.<br>
39//! Formatter gives an access to geometrical position of a symbol by the symbol index in the text.<br>
40//! Example of correspondence of some text symbol to an index in "row_1\n\nrow_2\n":<br>
41//! "row_1\n" - 0-5 indices;<br>
42//! "\n" - 6 index;<br>
43//! "\n" - 7 index;<br>
44//! "row_2\n" - 8-13 indices.<br>
45//! Pay attention that fonts should have the same LineSpacing value for correct formatting.<br>
46//! Example of the formatter using:
47//! @code
48//! Handle(Font_TextFormatter) aFormatter = new Font_TextFormatter();
49//! aFormatter->Append(text_1, aFont1);
50//! aFormatter->Append(text_2, aFont2);
51//! // setting of additional properties such as wrapping or alignment
52//! aFormatter->Format();
53//! @endcode
54class Font_TextFormatter : public Standard_Transient
a174a3c5 55{
a174a3c5 56public:
60f7b225 57 //! Iteration filter flags. Command symbols are skipped with any filter.
58 enum IterationFilter
59 {
60 IterationFilter_None = 0x0000, //!< no filter
61 IterationFilter_ExcludeInvisible = 0x0002, //!< exclude ' ', '\t', '\n'
62 };
63
64 //! Iterator through formatted symbols.
65 //! It's possible to filter returned symbols to have only significant ones.
66 class Iterator
67 {
68 public:
69 //! Constructor with initialization.
70 Iterator (const Font_TextFormatter& theFormatter,
71 IterationFilter theFilter = IterationFilter_None)
72 : myFilter (theFilter), myIter (theFormatter.myString.Iterator()), mySymbolChar (0), mySymbolCharNext (0)
73 {
74 mySymbolPosition = readNextSymbol (-1, mySymbolChar);
75 mySymbolNext = readNextSymbol (mySymbolPosition, mySymbolCharNext);
76 }
77
78 //! Returns TRUE if iterator points to a valid item.
79 Standard_Boolean More() const { return mySymbolPosition >= 0; }
80
81 //! Returns TRUE if next item exists
82 Standard_Boolean HasNext() const { return mySymbolNext >= 0; }
83
84 //! Returns current symbol.
85 Standard_Utf32Char Symbol() const { return mySymbolChar; }
86
87 //! Returns the next symbol if exists.
88 Standard_Utf32Char SymbolNext() const { return mySymbolCharNext; }
89
90 //! Returns current symbol position.
91 Standard_Integer SymbolPosition() const { return mySymbolPosition; }
92
93 //! Returns the next symbol position.
94 Standard_Integer SymbolPositionNext() const { return mySymbolNext; }
95
96 //! Moves to the next item.
97 void Next()
98 {
99 mySymbolPosition = mySymbolNext;
100 mySymbolChar = mySymbolCharNext;
101 mySymbolNext = readNextSymbol (mySymbolPosition, mySymbolCharNext);
102 }
103
104 protected:
105 //! Finds index of the next symbol
106 Standard_Integer readNextSymbol (const Standard_Integer theSymbolStartingFrom,
107 Standard_Utf32Char& theSymbolChar)
108 {
109 Standard_Integer aNextSymbol = theSymbolStartingFrom;
110 for (; *myIter != 0; ++myIter)
111 {
112 const Standard_Utf32Char aCharCurr = *myIter;
113 if (Font_TextFormatter::IsCommandSymbol (aCharCurr))
114 {
115 continue; // skip unsupported carriage control codes
116 }
117 aNextSymbol++;
118 if ((myFilter & IterationFilter_ExcludeInvisible) != 0)
119 {
120 if (aCharCurr == '\x0A'|| // LF (line feed, new line)
121 aCharCurr == ' ' ||
122 aCharCurr == '\t')
123 {
124 continue;
125 }
126 }
127 ++myIter;
128 theSymbolChar = aCharCurr;
129 return aNextSymbol; // found the first next, not command and not filtered symbol
130 }
131 return -1; // the next symbol is not found
132 }
133
134 protected:
135 IterationFilter myFilter; //!< possibility to filter not-necessary symbols
136 NCollection_Utf8Iter myIter; //!< the next symbol iterator value over the text formatter string
137 Standard_Integer mySymbolPosition; //!< the current position
138 Standard_Utf32Char mySymbolChar; //!< the current symbol
139 Standard_Integer mySymbolNext; //!< position of the next symbol in iterator, if zero, the iterator is finished
140 Standard_Utf32Char mySymbolCharNext; //!< the current symbol
141 };
a174a3c5 142
143 //! Default constructor.
317d68c9 144 Standard_EXPORT Font_TextFormatter();
a174a3c5 145
146 //! Setup alignment style.
147 Standard_EXPORT void SetupAlignment (const Graphic3d_HorizontalTextAlignment theAlignX,
148 const Graphic3d_VerticalTextAlignment theAlignY);
149
150 //! Reset current progress.
151 Standard_EXPORT void Reset();
152
153 //! Render specified text to inner buffer.
317d68c9 154 Standard_EXPORT void Append (const NCollection_String& theString,
155 Font_FTFont& theFont);
a174a3c5 156
157 //! Perform formatting on the buffered text.
158 //! Should not be called more than once after initialization!
159 Standard_EXPORT void Format();
160
60f7b225 161 Standard_DEPRECATED("BottomLeft should be used instead")
162 const NCollection_Vec2<Standard_ShortReal>& TopLeft (const Standard_Integer theIndex) const
317d68c9 163 {
60f7b225 164 return BottomLeft (theIndex);
317d68c9 165 }
a174a3c5 166
60f7b225 167 //! Returns specific glyph rectangle.
168 const NCollection_Vec2<Standard_ShortReal>& BottomLeft (const Standard_Integer theIndex) const
169 { return myCorners.Value (theIndex); }
170
317d68c9 171 //! Returns current rendering string.
172 inline const NCollection_String& String() const
173 {
174 return myString;
175 }
176
60f7b225 177 //! Returns symbol bounding box
178 //! @param bounding box.
179 Standard_EXPORT Standard_Boolean GlyphBoundingBox (const Standard_Integer theIndex,
180 Font_Rect& theBndBox) const;
181
182 //! Returns the line height
183 //! @param theIndex a line index, obtained by LineIndex()
184 Standard_ShortReal LineHeight (const Standard_Integer theIndex) const
185 { return theIndex == 0 ? myAscender : myLineSpacing; }
186
187 //! Returns width of a line
188 Standard_EXPORT Standard_ShortReal LineWidth (const Standard_Integer theIndex) const;
189
190 //! Returns true if the symbol by the index is '\n'. The width of the symbol is zero.
191 Standard_EXPORT Standard_Boolean IsLFSymbol (const Standard_Integer theIndex) const;
192
193 //! Returns position of the first symbol in a line using alignment
194 Standard_EXPORT Standard_ShortReal FirstPosition() const;
195
196 //! Returns column index of the corner index in the current line
197 Standard_EXPORT Standard_Integer LinePositionIndex (const Standard_Integer theIndex) const;
198
199 //! Returns row index of the corner index among text lines
200 Standard_EXPORT Standard_Integer LineIndex (const Standard_Integer theIndex) const;
201
317d68c9 202 //! Returns tab size.
203 inline Standard_Integer TabSize() const
204 {
205 return myTabSize;
206 }
a174a3c5 207
60f7b225 208 //! Returns horizontal alignment style
209 Graphic3d_HorizontalTextAlignment HorizontalTextAlignment() const { return myAlignX; }
210
211 //! Returns vertical alignment style
212 Graphic3d_VerticalTextAlignment VerticalTextAlignment() const { return myAlignY; }
213
214 //! Sets text wrapping width, zero means that the text is not bounded by width
215 void SetWrapping (const Standard_ShortReal theWidth) { myWrappingWidth = theWidth; }
216
217 //! Returns text maximum width, zero means that the text is not bounded by width
218 Standard_Boolean HasWrapping() const { return myWrappingWidth > 0; }
219
220 //! Returns text maximum width, zero means that the text is not bounded by width
221 Standard_ShortReal Wrapping() const { return myWrappingWidth; }
222
a174a3c5 223 //! @return width of formatted text.
224 inline Standard_ShortReal ResultWidth() const
225 {
226 return myBndWidth;
227 }
228
229 //! @return height of formatted text.
230 inline Standard_ShortReal ResultHeight() const
231 {
232 return myLineSpacing * Standard_ShortReal(myLinesNb);
233 }
234
60f7b225 235 //! @return maximum width of the text symbol
236 Standard_ShortReal MaximumSymbolWidth() const { return myMaxSymbolWidth; }
237
a174a3c5 238 //! @param bounding box.
d2eddacc 239 inline void BndBox (Font_Rect& theBndBox) const
a174a3c5 240 {
241 theBndBox.Left = 0.0f;
242 switch (myAlignX)
243 {
244 default:
245 case Graphic3d_HTA_LEFT: theBndBox.Right = myBndWidth; break;
246 case Graphic3d_HTA_RIGHT: theBndBox.Right = -myBndWidth; break;
247 case Graphic3d_HTA_CENTER:
248 {
249 theBndBox.Left = -0.5f * myBndWidth;
250 theBndBox.Right = 0.5f * myBndWidth;
251 break;
252 }
253 }
254 theBndBox.Top = myBndTop;
255 theBndBox.Bottom = theBndBox.Top - myLineSpacing * Standard_ShortReal(myLinesNb);
256 }
257
60f7b225 258 //! Returns internal container of the top left corners of a formatted rectangles.
259 const NCollection_Vector < NCollection_Vec2<Standard_ShortReal> >& Corners() const { return myCorners; }
260
261 //! Returns container of each line position at LF in formatted text
262 const NCollection_Vector<Standard_ShortReal>& NewLines() const { return myNewLines; }
263
264 //! Returns true if the symbol is CR, BEL, FF, NP, BS or VT
265 static inline Standard_Boolean IsCommandSymbol (const Standard_Utf32Char& theSymbol)
266 {
267 if (theSymbol == '\x0D' // CR (carriage return)
268 || theSymbol == '\a' // BEL (alarm)
269 || theSymbol == '\f' // FF (form feed) NP (new page)
270 || theSymbol == '\b' // BS (backspace)
271 || theSymbol == '\v') // VT (vertical tab)
272 return Standard_True;
273
274 return Standard_False;
275 }
276
277 DEFINE_STANDARD_RTTIEXT (Font_TextFormatter, Standard_Transient)
278
a174a3c5 279protected: //! @name class auxiliary methods
280
281 //! Move glyphs on the current line to correct position.
60f7b225 282 Standard_EXPORT void newLine (const Standard_Integer theLastRect,
283 const Standard_ShortReal theMaxLineWidth);
a174a3c5 284
285protected: //! @name configuration
286
287 Graphic3d_HorizontalTextAlignment myAlignX; //!< horizontal alignment style
288 Graphic3d_VerticalTextAlignment myAlignY; //!< vertical alignment style
289 Standard_Integer myTabSize; //!< horizontal tabulation width (number of space symbols)
60f7b225 290 Standard_ShortReal myWrappingWidth; //!< text is wrapped by the width if defined (more 0)
291 Standard_ShortReal myLastSymbolWidth; //!< width of the last symbol
292 Standard_ShortReal myMaxSymbolWidth; //!< maximum symbol width of the formatter string
a174a3c5 293
294protected: //! @name input data
295
296 NCollection_String myString; //!< currently rendered text
317d68c9 297 NCollection_Vec2<Standard_ShortReal>
298 myPen; //!< current pen position
299 NCollection_Vector < NCollection_Vec2<Standard_ShortReal> >
60f7b225 300 myCorners; //!< The bottom left corners of a formatted rectangles.
a174a3c5 301 NCollection_Vector<Standard_ShortReal>
302 myNewLines; //!< position at LF
303 Standard_ShortReal myLineSpacing; //!< line spacing (computed as maximum of all fonts involved in text formatting)
60f7b225 304 Standard_ShortReal myAscender; //!< line spacing for the first line
a174a3c5 305 bool myIsFormatted; //!< formatting state
306
a174a3c5 307protected: //! @name temporary variables for formatting routines
308
309 Standard_Integer myLinesNb; //!< overall (new)lines number (including splitting by width limit)
310 Standard_Integer myRectLineStart; //!< id of first rectangle on the current line
a174a3c5 311 Standard_Integer myNewLineNb;
312
313 Standard_ShortReal myPenCurrLine; //!< current baseline position
a174a3c5 314 Standard_ShortReal myBndTop;
315 Standard_ShortReal myBndWidth;
317d68c9 316 NCollection_Vec2<Standard_ShortReal>
317 myMoveVec; //!< local variable
a174a3c5 318};
319
317d68c9 320#endif // Font_TextFormatter_Header