Log in to reply
 

[NATIVE] Get text width correctly?



  • Hi,

    I'm working on an experimental menu library and I'm struggling with the _END_TEXT_COMMAND_GET_WIDTH native (formerly known as _GET_TEXT_SCREEN_WIDTH) which has a strange behaviour. It returns a float value that is supposed to be the total text length passed in as a parameter. Not sure if this is the proper way to do it, or if I'm missing some function before returning the value, unfortunately the research and documentation is weak on this one.

    float MenuHelper::GetStringWidth(const std::string text)
    {
    	UI::_SET_TEXT_ENTRY_FOR_WIDTH("STRING");
    	UI::_ADD_TEXT_COMPONENT_STRING((char*)text.c_str());
    	UI::SET_TEXT_FONT(FontChaletLondon);
    	UI::SET_TEXT_SCALE(0.0f, 0.45f);
    	float width = UI::_GET_TEXT_SCREEN_WIDTH(1);
    }
    

    Result in game (rectangle is the actual string width, units are in real screen coords but it doesn't matter) :

    alt text

    alt text

    As you can see, the 'sample text' has an extra blank space, actually every character seems to have this extra space right after itself. I've tried writing a formula to compensate and remove that blank space, but it won't work on other game resolutions unless I try to find out every width char for every font in the game. Decompiled scripts using that native do not have a plain text example unfortunately..

    Any ideas?


  • MODERATOR

    @winject
    Hmm, I have not noticed this issue, but getting the string width to measure how many rectangles I need to draw seems to work without issue; the string wraps nicely within the width of my rectangle(s). This is the code, which is mostly from NativeUI + ikt's menu base:

    private static void AddLongString(string str)
            {
                const int strLen = 99;
                for (int i = 0; i < str.Length; i += strLen)
                {
                    string substr = str.Substring(i, Math.Min(strLen, str.Length - i));
                    Function.Call(Hash._ADD_TEXT_COMPONENT_STRING, substr); //ADD_TEXT_COMPONENT_SUBSTRING_PLAYER_NAME
                }
            }
    
    public static float MeasureStringWidth(string str, GTA.Font font, float fontsize) //convert to pixel width
            {
                //int screenw = 2560;// Game.ScreenResolution.Width;
                //int screenh = 1440;// Game.ScreenResolution.Height;
                const float height = 1080f;
                float ratio = (float)Game.ScreenResolution.Width / Game.ScreenResolution.Height;
                float width = height * ratio;
                return MeasureStringWidthNoConvert(str, font, fontsize) * width;
            }
            
    private static float MeasureStringWidthNoConvert(string str, GTA.Font font, float fontsize)
            {
                Function.Call((Hash)0x54CE8AC98E120CAB, "STRING"); //_BEGIN_TEXT_COMMAND_WIDTH
                AddLongString(str);
                Function.Call(Hash.SET_TEXT_FONT, (int)font);
                Function.Call(Hash.SET_TEXT_SCALE, fontsize, fontsize);
                return Function.Call<float>(Hash._0x85F061DA64ED2F67, true); //_END_TEXT_COMMAND_GET_WIDTH
            }
    

    In my DrawText method I use SET_TEXT_SCALE like so:

            Function.Call(Hash.SET_TEXT_SCALE, 1.0f, FontSize);
    

    Rectangle width is also in pixels. Pseudo-code:

    int pixelWidth = 900;
    
    const float height = 1080f;
    float ratio = (float)Game.ScreenResolution.Width / Game.ScreenResolution.Height;
    var width = height * ratio;
    
    pixelWidth / width = the width param in DRAW_RECT
    

    I just realized that I was under the assumption that you need this for word wrapping/long descriptions; if that's not the case, my mistake :open_mouth:



  • Hey, that's exactly like how I did it.

    float Menu::getStringWidth(std::string text, float scale, int font) {
    	UI::_SET_TEXT_ENTRY_FOR_WIDTH("STRING");
    	UI::ADD_TEXT_COMPONENT_SUBSTRING_PLAYER_NAME(CharAdapter(text));
    	UI::SET_TEXT_FONT( font);
    	UI::SET_TEXT_SCALE( scale, scale);
    	return UI::_GET_TEXT_SCREEN_WIDTH(true);
    }
    
    void thing() { 
    	
    	showText(0.1, 0.1, 1.0, "Hello world!", 0, solidWhite, true);
    	float len = menu.getStringWidth("Hello world!", 1.0f, 0);
    	GRAPHICS::DRAW_RECT(0.1f + len / 2.0f, 0.175f, len, 0.01f, 255, 0, 0, 255);
    
    	showText(0.1f, 0.2f, 0.5f, "Hello world!", 1, solidWhite, true);
    	len = menu.getStringWidth("Hello world!", 0.5f, 1);
    	GRAPHICS::DRAW_RECT(0.1f + len / 2.0f, 0.235f, len, 0.005f, 255, 0, 0, 255);
    
    }
    

    img



  • @stillhere @ikt I had glanced quickly at NativeUI's code and SHVDN source to see how it was exactly performed but I couldn't reproduce the same result. After some thorough research, I figured out two natives were conflicting in my source code:

    • GET_SCREEN_RESOLUTION
    • _GET_ACTIVE_SCREEN_RESOLUTION

    I use them to convert the weird native internal coords into real screen coordinates (with correct width and height) and surprisingly I was calling the wrong one before the DRAW_RECT native.

    The first native doesn't return the game resolution itself but something related to the screen. However, the second one will always return the game resolution, for example if you change your resolution in game, it will display the new game resolution.

    I just realized that I was under the assumption that you need this for word wrapping/long descriptions;

    It was actually for my window class, the current width is fixed manually and I wanted to make it modular and update its width according to the longest string element.

    GRAPHICS::DRAW_RECT(0.1f + len / 2.0f, 0.175f, len, 0.01f, 255, 0, 0, 255); 
    

    Seems exactly what I needed! I saw in some decompiled script the "ESMINDOLLA" (special dollar text entry) length was also being divided by two when using the HouseScript font, I thought it was random or just related to that font, turns out I moved on too fast.

    Thank you both for taking your time to answer!

    Greets,

    winject



  • fyi the coords of the rectangle are center, the coords of the text is top-left, hence the rect position being offset by half the text length. You can add additional padding of any size to make a centered text box around it



  • @ikt said in [NATIVE] Get text width correctly?:

    fyi the coords of the rectangle are center, the coords of the text is top-left, hence the rect position being offset by half the text length. You can add additional padding of any size to make a centered text box around it

    I see, well I'm using top-left for both and it seems to work correctly now. By the way, I noticed I was passing the wrong font size in the parameters the whole time besides the resolution issue..

    Here's the result with all resolutions :
    alt text


Log in to reply
 

Looks like your connection to GTA5-Mods.com Forums was lost, please wait while we try to reconnect.