@@ -271,4 +271,105 @@ int16_t Graphics::width()
271271int16_t Graphics::height ()
272272{
273273 return _height;
274- };
274+ };
275+
276+
277+ /* *
278+ * @brief Draws a text box with optional border and word-wrapped content
279+ *
280+ * @param int16_t x0
281+ * Top-left x-coordinate of the text box
282+ * @param int16_t y0
283+ * Top-left y-coordinate of the text box
284+ * @param int16_t x1
285+ * Bottom-right x-coordinate of the text box
286+ * @param int16_t y1
287+ * Bottom-right y-coordinate of the text box
288+ * @param const char* text
289+ * The null-terminated string to be rendered inside the box
290+ * @param uint16_t textSizeMultiplier
291+ * Size multiplier for the text
292+ * @param const GFXfont* font
293+ * Pointer to the font to use for rendering the text
294+ * @param uint16_t verticalSpacing
295+ * Vertical spacing (in pixels) between lines of text; if 0 or NULL, defaults to text height + padding
296+ * @param bool showBorder
297+ * Whether to draw a border around the text box
298+ * @param uint16_t fontSize
299+ * Font size in points (pt)
300+ *
301+ * @details This function renders a block of text inside the defined rectangular area.
302+ * It automatically wraps words to the next line if they exceed the available width.
303+ * If the text does not fit entirely, an ellipsis ("...") is added to the final visible line.
304+ * Text is padded with spaces to keep a consistent line length.
305+ */
306+ void Graphics::drawTextBox (int16_t x0,int16_t y0,int16_t x1,int16_t y1, const char * text,uint16_t textSizeMultiplier, const GFXfont *font, uint16_t verticalSpacing, bool showBorder, uint16_t fontSize )
307+ {
308+ int16_t currentX = x0;
309+ int16_t currentY = y0;
310+
311+ int16_t textLenght=strlen (text);
312+ int offset=0 ;
313+ fontSize=(fontSize*3 )/4 ; // 1pt = 4/3 px
314+ int numOfCharactersPerLine=(x1-x0)/(textSizeMultiplier*fontSize);
315+ int16_t currentLineLenght=numOfCharactersPerLine;
316+ this ->setTextSize (textSizeMultiplier);
317+ this ->setFont (font);
318+ if (showBorder)
319+ {
320+ this ->drawRect (x0,y0,(x1-x0),(y1-y0),1 );
321+ }
322+ if (verticalSpacing==NULL )
323+ {
324+ verticalSpacing=textSizeMultiplier*fontSize+6 ;
325+ }
326+ for (int i = y0; i < (y1 - verticalSpacing); i += verticalSpacing)
327+ {
328+ currentY = i;
329+ this ->setCursor (currentX, currentY);
330+
331+ int remainingLength = textLenght - offset;
332+ int lineLength = (remainingLength < currentLineLenght) ? remainingLength : currentLineLenght;
333+
334+ // Temporary buffer to hold potential line
335+ char * buffer = (char *)malloc ((lineLength + 1 ) * sizeof (char ));
336+ memcpy (buffer, text + offset, lineLength);
337+ buffer[lineLength] = ' \0 ' ;
338+
339+ // Find the last space in buffer to wrap at word boundary
340+ int lastSpaceIndex = -1 ;
341+ for (int j = 0 ; j < lineLength; ++j) {
342+ if (buffer[j] == ' ' ) lastSpaceIndex = j;
343+ }
344+
345+ // If a word gets cut, wrap to the next line
346+ if ((offset + lineLength < textLenght) && (text[offset + lineLength] != ' ' ) && (lastSpaceIndex != -1 ) && ((i + verticalSpacing) < (y1 - verticalSpacing))) {
347+ lineLength = lastSpaceIndex + 1 ; // Include the space
348+ }
349+
350+ // Allocate space for actual line with null-terminator
351+ char * textPart = (char *)malloc ((currentLineLenght + 1 ) * sizeof (char ));
352+ memset (textPart, ' ' , currentLineLenght); // Fill with spaces
353+ memcpy (textPart, text + offset, lineLength); // Copy valid part
354+ textPart[currentLineLenght] = ' \0 ' ;
355+
356+ // Ellipsis on final visible line
357+ if ((i + verticalSpacing) >= (y1 - verticalSpacing) && (offset + lineLength < textLenght)) {
358+
359+
360+ textPart[currentLineLenght - 1 ] = ' .' ;
361+ textPart[currentLineLenght - 2 ] = ' .' ;
362+ textPart[currentLineLenght - 3 ] = ' .' ;
363+ }
364+
365+ this ->print (textPart);
366+
367+ offset += lineLength;
368+ free (buffer);
369+ free (textPart);
370+
371+ if (offset >= textLenght) return ;
372+ }
373+
374+
375+ }
0 commit comments