| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 | /*  * (c) Philippe G. 2019, philippe_44@outlook.com * * This software is released under the MIT License. * https://opensource.org/licenses/MIT *  */#include <string.h>#include <ctype.h>#include <stdint.h>#include <arpa/inet.h>#include "esp_log.h"#include "gds_private.h"#include "gds.h"#include "gds_draw.h"#include "gds_text.h"#define max(a,b) (((a) > (b)) ? (a) : (b))static char TAG[] = "gds";/**************************************************************************************** *  Set fonts for each line in text mode */static const struct GDS_FontDef *GuessFont( struct GDS_Device *Device, int FontType) {	switch(FontType) {	case GDS_FONT_LINE_1:			return &Font_line_1;	case GDS_FONT_LINE_2:			return &Font_line_2;	case GDS_FONT_SMALL:			return &Font_droid_sans_fallback_11x13;		case GDS_FONT_MEDIUM:				default:				return &Font_droid_sans_fallback_15x17;	#ifdef USE_LARGE_FONTS	case GDS_FONT_LARGE:			return &Font_droid_sans_fallback_24x28;		break;			case GDS_FONT_SEGMENT:					if (Device->Height == 32) return &Font_Tarable7Seg_16x32;		else return &Font_Tarable7Seg_32x64;#else	case GDS_FONT_LARGE:		case GDS_FONT_SEGMENT:					ESP_LOGW(TAG, "large fonts disabled");		return &Font_droid_sans_fallback_15x17;		break;		#endif		}}/**************************************************************************************** *  Set fonts for each line in text mode */bool GDS_TextSetFontAuto(struct GDS_Device* Device, int N, int FontType, int Space) {	const struct GDS_FontDef *Font = GuessFont( Device, FontType );	return GDS_TextSetFont( Device, N, Font, Space );}/**************************************************************************************** *  Set fonts for each line in text mode */bool GDS_TextSetFont(struct GDS_Device* Device, int N, const struct GDS_FontDef *Font, int Space) {	if (--N >= MAX_LINES) return false;	Device->Lines[N].Font = Font;		// re-calculate lines absolute position	Device->Lines[N].Space = Space;	Device->Lines[0].Y = Device->Lines[0].Space;	for (int i = 1; i <= N; i++) Device->Lines[i].Y = Device->Lines[i-1].Y + Device->Lines[i-1].Font->Height + Device->Lines[i].Space;			ESP_LOGI(TAG, "Adding line %u at %d (height:%u)", N + 1, Device->Lines[N].Y, Device->Lines[N].Font->Height);		if (Device->Lines[N].Y + Device->Lines[N].Font->Height > Device->Height) {		ESP_LOGW(TAG, "line does not fit display");		return false;	}		return true;}/**************************************************************************************** *  */bool GDS_TextLine(struct GDS_Device* Device, int N, int Pos, int Attr, char *Text) {	int Width, X = Pos;	// counting 1..n	N--;		GDS_SetFont( Device, Device->Lines[N].Font );		if (Attr & GDS_TEXT_MONOSPACE) GDS_FontForceMonospace( Device, true );		Width = GDS_FontMeasureString( Device, Text );		// adjusting position, erase only EoL for rigth-justified	if (Pos == GDS_TEXT_RIGHT) X = Device->Width - Width - 1;	else if (Pos == GDS_TEXT_CENTER) X = (Device->Width - Width) / 2;		// erase if requested	if (Attr & GDS_TEXT_CLEAR) {		int Y_min = max(0, Device->Lines[N].Y), Y_max = max(0, Device->Lines[N].Y + Device->Lines[N].Font->Height);		for (int c = (Attr & GDS_TEXT_CLEAR_EOL) ? X : 0; c < Device->Width; c++) 			for (int y = Y_min; y < Y_max; y++)				DrawPixelFast( Device, c, y, GDS_COLOR_BLACK );	}			GDS_FontDrawString( Device, X, Device->Lines[N].Y, Text, GDS_COLOR_WHITE );		ESP_LOGD(TAG, "displaying %s line %u (x:%d, attr:%u)", Text, N+1, X, Attr);		// update whole display if requested	Device->Dirty = true;	if (Attr & GDS_TEXT_UPDATE) GDS_Update( Device );			return Width + X < Device->Width;}/**************************************************************************************** * Try to align string for better scrolling visual. there is probably much better to do */int GDS_TextStretch(struct GDS_Device* Device, int N, char *String, int Max) {	char Space[] = "     ";	int Len = strlen(String), Extra = 0, Boundary;		N--;		// we might already fit	GDS_SetFont( Device, Device->Lines[N].Font );		if (GDS_FontMeasureString( Device, String ) <= Device->Width) return 0;			// add some space for better visual 	strncat(String, Space, Max-Len);	String[Max] = '\0';	Len = strlen(String);		// mark the end of the extended string	Boundary = GDS_FontMeasureString( Device, String );				// add a full display width		while (Len < Max && GDS_FontMeasureString( Device, String ) - Boundary < Device->Width) {		String[Len++] = String[Extra++];		String[Len] = '\0';	}			return Boundary;}/**************************************************************************************** *  */void GDS_TextPos(struct GDS_Device* Device, int FontType, int Where, int Attr, char *Text, ...) {	va_list args;	TextAnchor Anchor = TextAnchor_Center;			if (Attr & GDS_TEXT_CLEAR) GDS_Clear( Device, GDS_COLOR_BLACK );		if (!Text) return;		va_start(args, Text);		switch(Where) {	case GDS_TEXT_TOP_LEFT: 	default:		Anchor = TextAnchor_NorthWest; 		break;	case GDS_TEXT_MIDDLE_LEFT:		Anchor = TextAnchor_West;		break;	case GDS_TEXT_BOTTOM_LEFT:		Anchor = TextAnchor_SouthWest;		break;	case GDS_TEXT_CENTERED:		Anchor = TextAnchor_Center;		break;	}			ESP_LOGD(TAG, "Displaying %s at %u with attribute %u", Text, Anchor, Attr);		GDS_SetFont( Device, GuessFont( Device, FontType ) );		GDS_FontDrawAnchoredString( Device, Anchor, Text, GDS_COLOR_WHITE );		Device->Dirty = true;	if (Attr & GDS_TEXT_UPDATE) GDS_Update( Device );		va_end(args);}
 |