[Tutorial] Short: Calculating width of textdraws
#1

Hi all,

This is a super short one - I wanted to chronicle my research somewhere to save someone the hassle of spending however long I have trying to tackle this problem: working out how wide a textdraw actually is based on its text content.

In my case, I have a UI system with textboxes and the likes - and I wanted to shorten the string down if it was longer then the textbox, so using the below, if the text width is greater than the width of the textbox, I cut off the remainder, the size of three .'s and some padding, resulting in:



Another use case would be if you wanted to put "hyperlinks" in your textdraw contents - so that you can trigger things once a certain word is pressed without having to manually work out and hard code position.

Solution:
1. The GTA San Andreas\data\fonts.dat file contains (in cleartext) the baseline widths of each character in rows of 8 - where the 1st digit on the left reflects the first character after the # and the first number. For example, ! is 15 pixels wide.

Code:
15   9  17  27  20  34  23  12	  #	0    ! " Ј $ % & '
12  12  21  20  12  14  12  15	  #	8  ( ) * + , - . /
23  15  21  21  21  21  21  21	  #	16 0 1 2 3 4 5 6 7
20  21  12  12  24  24  24  19	  #	24 8 9 : ; < = > ?
10  22  19  19  22  16  19  24	  #	32 tmA B C D E F G
22  11  16  21  15  28  24  27	  #	40 H I J K L M N O
20  25  19  19  18  23  23  31	  #	48 P Q R S T U V W
23  19  21  21  13  35  11  21	  #	56 X Y Z       ! _
10  19  20  14  20  19  13  20	  #	64 ! a b c d e f g
19   9   9  19   9  29  19  21	  #	72 h i j k l m n o
19  19  15  15  14  18  19  27	  #	80 p q r s t u v w
20  20  17  21  17  20  15  15	  #	88 x y z     $ [ ]
22  22  22  22  29  19  16  16	  #	96 А Б В Г Ж З И Й
16  16  11  11  11  11  27  27	  #	104 К Л М Н О П Т У 
27  27  23  23  23  23  20  19	  #	112 Ф Ц Щ Ъ Ы Ь Я а
19  19  19  30  14  19  19  19	  #	120 б в г ж з и й к
19   9   9   9   9  21  21  21	  #	128 л м н о п т у ф
21  18  18  18  18  24  19  19	  #	136 ц щ ъ ы ь С с ї
20  18  19  19  21  19  19  19	  #	144 0 1 2 3 4 5 6 7
19  19  16  19  19  19  20  19	  #	152 8 9 : A B C D E
16  19  19   9  19  20  14  29	  #	160 F G H I J K L M
19  19  19  19  19  19  21  19	  #	168 N O P Q R S T U
20  32  21  19  19  19  19  19	  #	176 V W X Y Z А Б В
19  29  19  19  19  19  19   9	  #	184 Г Ж З И Й К Л М
 9   9   9  19  19  19  19  19	  #	192 Н О П Т У Ф Ц Щ
19  19  19  19  21  19  10   9	  #	200 Ъ Ы Ь Я С ї ' .
2. There are however two things to note:
- These are multiplied against the textdraw width - for example, at 0.5 the actual width of the ! character is 7.5 - not 15.
- These also work off the basis of the virtual 640x480 textdraw canvas which applies regardless of resolution. For example, at 1280x1024, the letter ! at 1.0 letter width will ACTUALLY be 30 pixels wide on your screen. However most of the time this shouldn't matter because all other textdraws will also be drawn on the 640x480 grid; I include this only so that you all have a proper understanding of why this is.

3. The default unproportional letter width is 20 pixels.
Reply
#2

Very useful. This could even be used for properly splitting chat lines!



Put it in an include. A VERY simple include:

pawn Code:
#define IsTextdrawChar(%0) \
    (!!(0 <= %0 < 224))

#define GetCharLength(%0) \
    (IsTextdrawChar(%0) ? _letterSizes[%0] : 0)

new Float:_letterSizes[224] = {
    15.0,   9.0,  17.0,  27.0,  20.0,  34.0,  23.0,  12.0,  //   ! " Ј $ % & '
    12.0,  12.0,  21.0,  20.0,  12.0,  14.0,  12.0,  15.0,  // ( ) * + , - . /
    23.0,  15.0,  21.0,  21.0,  21.0,  21.0,  21.0,  21.0,  // 0 1 2 3 4 5 6 7
    20.0,  21.0,  12.0,  12.0,  24.0,  24.0,  24.0,  19.0,  // 8 9 : ; < = > ?
    10.0,  22.0,  19.0,  19.0,  22.0,  16.0,  19.0,  24.0,  // tmA B C D E F G
    22.0,  11.0,  16.0,  21.0,  15.0,  28.0,  24.0,  27.0,  // H I J K L M N O
    20.0,  25.0,  19.0,  19.0,  18.0,  23.0,  23.0,  31.0,  // P Q R S T U V W
    23.0,  19.0,  21.0,  21.0,  13.0,  35.0,  11.0,  21.0,  // X Y Z       ! _
    10.0,  19.0,  20.0,  14.0,  20.0,  19.0,  13.0,  20.0,  // ! a b c d e f g
    19.0,   9.0,   9.0,  19.0,   9.0,  29.0,  19.0,  21.0,  // h i j k l m n o
    19.0,  19.0,  15.0,  15.0,  14.0,  18.0,  19.0,  27.0,  // p q r s t u v w
    20.0,  20.0,  17.0,  21.0,  17.0,  20.0,  15.0,  15.0,  // x y z     $ [ ]
    22.0,  22.0,  22.0,  22.0,  29.0,  19.0,  16.0,  16.0,  // А Б В Г Ж З И Й
    16.0,  16.0,  11.0,  11.0,  11.0,  11.0,  27.0,  27.0,  // К Л М Н О П Т У
    27.0,  27.0,  23.0,  23.0,  23.0,  23.0,  20.0,  19.0,  // Ф Ц Щ Ъ Ы Ь Я а
    19.0,  19.0,  19.0,  30.0,  14.0,  19.0,  19.0,  19.0,  // б в г ж з и й к
    19.0,   9.0,   9.0,   9.0,   9.0,  21.0,  21.0,  21.0,  // л м н о п т у ф
    21.0,  18.0,  18.0,  18.0,  18.0,  24.0,  19.0,  19.0,  // ц щ ъ ы ь С с ї
    20.0,  18.0,  19.0,  19.0,  21.0,  19.0,  19.0,  19.0,  // 0 1 2 3 4 5 6 7
    19.0,  19.0,  16.0,  19.0,  19.0,  19.0,  20.0,  19.0,  // 8 9 : A B C D E
    16.0,  19.0,  19.0,   9.0,  19.0,  20.0,  14.0,  29.0,  // F G H I J K L M
    19.0,  19.0,  19.0,  19.0,  19.0,  19.0,  21.0,  19.0,  // N O P Q R S T U
    20.0,  32.0,  21.0,  19.0,  19.0,  19.0,  19.0,  19.0,  // V W X Y Z А Б В
    19.0,  29.0,  19.0,  19.0,  19.0,  19.0,  19.0,   9.0,  // Г Ж З И Й К Л М
     9.0,   9.0,   9.0,  19.0,  19.0,  19.0,  19.0,  19.0,  // Н О П Т У Ф Ц Щ
    19.0,  19.0,  19.0,  19.0,  21.0,  19.0,  10.0,   9.0   // Ъ Ы Ь Я С ї ' .
};
Reply
#3

Oh god, so useful
Reply
#4

Yep, usefull
Reply
#5

Someone extract the sizes for the dialog font...
Reply
#6

Uh i didn't saw this before, but i made include for dialog center text with smilar way.. i made all letters width..

https://sampforum.blast.hk/showthread.php?tid=625090
Reply
#7

This works for ASCII:
Code:
new const characterWidths[] = {
	//Data taken from singleplayer fonts.dat file
	 0,  15,  15,  15,  15,  15,  15,  15,	//NULL is not displayable because it breaks off the string, others display as a space
	15,  15,  15,  15,  15,  15,  15,  15,  //Display as a space
	15,  15,  15,  15,  15,  15,  15,  15,  //Display as a space
	15,  15,  15,  15,  15,  15,  15,  15,  //Display as a space
	15,   9,  17,  27,  20,  34,  23,  12,	//  ! " Ј $ % & '
	12,  12,  21,  20,  12,  14,  12,  15,	//( ) * + , - . /
	23,  15,  21,  21,  21,  21,  21,  21,	//0 1 2 3 4 5 6 7
	20,  21,  12,  12,  24,  24,  24,  19,	//8 9 : ; < = > ?
	10,  22,  19,  19,  22,  16,  19,  24,	//tmA B C D E F G
	22,  11,  16,  21,  15,  28,  24,  27,	//H I J K L M N O
	20,  25,  19,  19,  18,  23,  23,  31,	//P Q R S T U V W
	23,  19,  21,  21,  13,  35,  11,  21,	//X Y Z       ! _
	10,  19,  20,  14,  20,  19,  13,  20,	//! a b c d e f g
	19,   9,   9,  19,   9,  29,  19,  21,	//h i j k l m n o
	19,  19,  15,  15,  14,  18,  19,  27,	//p q r s t u v w
	20,  20,  17,  21,  17,  20,  15,  15,	//x y z     $ [ ]
	22,  22,  22,  22,  29,  19,  16,  16,	//А Б В Г Ж З И Й
	16,  16,  11,  11,  11,  11,  27,  27,	//К Л М Н О П Т У
	27,  27,  23,  23,  23,  23,  20,  19,	//Ф Ц Щ Ъ Ы Ь Я а
	19,  19,  19,  30,  14,  19,  19,  19,	//б в г ж з и й к
	19,   9,   9,   9,   9,  21,  21,  21,	//л м н о п т у ф
	21,  18,  18,  18,  18,  24,  19,  19,	//ц щ ъ ы ь С с ї
	20,  18,  19,  19,  21,  19,  19,  19,	//0 1 2 3 4 5 6 7
	19,  19,  16,  19,  19,  19,  20,  19,	//8 9 : A B C D E
	16,  19,  19,   9,  19,  20,  14,  29,	//F G H I J K L M
	19,  19,  19,  19,  19,  19,  21,  19,	//N O P Q R S T U
	20,  32,  21,  19,  19,  19,  19,  19,	//V W X Y Z А Б В
	19,  29,  19,  19,  19,  19,  19,   9,	//Г Ж З И Й К Л М
	 9,   9,   9,  19,  19,  19,  19,  19,	//Н О П Т У Ф Ц Щ
	19,  19,  19,  19,  21,  19,  10,   9	//Ъ Ы Ь Я С ї ' .
};
stock GetCharacterWidth© {
	if(c < 0) {
	    return 0;
	}
	if(c >= sizeof(characterWidths)) {
	    return 20; //Default width, also taken from singleplayer fonts.dat file
	}
	return characterWidths[c];
}
stock GetStringWidth(const string[]) {
	new width = 0;
	for(new i = 0, size = strlen(string); i < size; i++) {
	    width += GetCharacterWidth(string[i]);
	}
	return width;
}
Btw, ! is not 15, but space is. ! is 9.
And the widths should be multiplied by the texdraw letter size, not the texdraw width.

EDIT:
Usage for a single character is:
Code:
printf("%d", GetCharacterWidth('a'));
Usage for a string is:
Code:
printf("%d", GetStringWidth("abc"));
EDIT2:
Keep in mind that the final values depend on TextDrawLetterSize and TextDrawSetOutline.
Also don't forget to set TextDrawSetProportional to 1.
Reply
#8

I took some time to create a proper implementation of this concept. The ones posted here don't take into account that there are four different fonts, etc. I explained this further in my thread: https://sampforum.blast.hk/showthread.php?tid=660047
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)