Jump to content

gdispGFillStringBoxAutoScale


Recommended Posts

Hi,

I have a little attribution to ugfx. This function draws a text in a given box, similar to gdispGFillStringBox, but the optimal font is chosen so the text fits into the box with the least lines.
The user can select a subset of fonts by passing a font name with a wildcard in place of the size. Example 'DejaVuSans*'

This function must be placed in gdisp.c and gdisp.h as it uses static functions declared there.One must also place a copy of 'matchfont2' function (from gdisp_font.c) in gdisp.c, since it is declared static as well.

I hope someone can make use of this and I am of course looking forward to comments.

If anyone is interested: I also have a version of this that saves the wrapping parameters, so faster redraw is possible...

 

gdisp.h

/** \brief Draws a string vertically centered within the specified box. The font size is chosen to make sure the whole text fits in the box
 *  \pre  GDISP_NEED_TEXT and GDISP_NEED_TEXT_WORDWRAP must be TRUE in your gfxconf.h
 *  \note   This uses word wrap to find the largest font to determine how many lines are needed. Fonts are passed using their short name with wildcard *
 *          instead of the number. e.g.: DejaVuSans*
 *          Text will not be rendered if it could not be fitted inside the specified box
 *
 * \param g             The display to use
 * \param x,y           The position for the text
 * \param cx,cy		    The width and height of the box
 * \param str           The string to draw
 * \param fontNames     Short name of fonts to use + wildcard *
 * \param color         The color to use
 * \param bgcolor       The background color to use
 * \param justify       Justify the text left, center or right within the box
 * \return bool_t       Returns TRUE if the text could be fitted inside the box, FALSE otherwise
 *
 */
#if GDISP_NEED_TEXT_WORDWRAP
bool_t gdispGFillStringBoxAutoScale(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, const char* fontNames, color_t color, color_t bgcolor, justify_t justify);
#define	gdispFillStringBoxAutoScale(x,y,cx,cy,s,f,c,b,j)			gdispGFillStringBoxAutoScale(GDISP,x,y,cx,cy,s,f,c,b,j)
#endif //NEEDS_WORDWRAP

 


#if GDISP_NEED_TEXT_WORDWRAP
bool_t gdispGFillStringBoxAutoScale(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, const char* fontNames, color_t color, color_t bgcolor, justify_t justify) {

        wrapParameters_t wrapParameters;

        font_t resFont = 0;
        uint16_t resLines = 0;

		MUTEX_ENTER(g);

		g->p.cx = cx;
		g->p.cy = cy;
		g->t.clipx0 = g->p.x = x;
		g->t.clipy0 = g->p.y = y;
		g->t.clipx1 = x+cx;
		g->t.clipy1 = y+cy;
		g->t.color = color;
		g->t.bgcolor = g->p.color = bgcolor;

		TEST_CLIP_AREA(g) {

			// background fill
			fillarea(g);

			//get available fonts
            const struct mf_font_list_s *fp = mf_get_font_list();

            for(;fp ;fp = fp->next) //iterate over all fonts
            {
                if((fp->font->line_height <= cy) && matchfont2(fontNames,fp->font->short_name))
                {
                    // Count the number of lines needed by this font
                    uint16_t nbrLines = 0;
                    mf_wordwrap(fp->font, cx, str, mf_countline_callback, &nbrLines);

                    if(cy / nbrLines >= fp->font->line_height)   //is there space for this font?
                    {
                        //find the largest fitting font
                        if((resFont == 0) || (fp->font->line_height > resFont->line_height))
                        {
                            resFont = fp->font;
                            resLines = nbrLines;
                        }
                    }
                }
            }

            if(!resFont) //found no font that fits all the text in this area
                return FALSE;


            /* Select the anchor position */
			switch(justify) {
			case justifyCenter:
				x += (cx + 1) / 2;
				break;
			case justifyRight:
				x += cx;
				break;
			default:	// justifyLeft
				x += resFont->baseline_x;
				break;
			}

			/* Render */
            wrapParameters.x = x;
            wrapParameters.y = y;
            wrapParameters.font = resFont;
            wrapParameters.justify = justify;
            wrapParameters.g = g;
            g->t.font = resFont;

            wrapParameters.y += (cy+1 - resLines*resFont->height)/2;
            mf_wordwrap(resFont, cx, str, mf_fillline_callback, &wrapParameters);

		}

		autoflush(g);
		MUTEX_EXIT(g);

		return TRUE;
	}
#endif //NEEDS_WORDWRAP
/From gdisp_font.c, can not access, because it is static so there is a copy here..
static bool_t matchfont2(const char *pattern, const char *name) {
	while(1) {
		switch (pattern[0]) {
		case '*':
			if (name[0] == 0)
				return pattern[1] == 0;
			if (pattern[1] == name[0])
				pattern++;
			else
				name++;
			break;
		case 0:
			return name[0] == 0;
		default:
			if (name[0] != pattern[0])
				return FALSE;
			pattern++;
			name++;
			break;
		}
	}
}

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...