Skip to content

[FEATURE] Expose GuiLoadStyleFromMemory #548

Description

@jgabaut

Request

I would like to use the GuiLoadStyleFromMemory function.

Currently, the GuiLoadStyleFromMemory function is private and not available to usercode.

  • static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize)

    They must resort to GuiLoadStyleFromFile (which, ultimately, still uses GuiLoadStyleFromMemory):
  • raygui/src/raygui.h

    Lines 4372 to 4477 in 6d2b28f

    void GuiLoadStyle(const char *fileName)
    {
    #define MAX_LINE_BUFFER_SIZE 256
    bool tryBinary = false;
    if (!guiStyleLoaded) GuiLoadStyleDefault();
    // Try reading the files as text file first
    FILE *rgsFile = fopen(fileName, "rt");
    if (rgsFile != NULL)
    {
    char buffer[MAX_LINE_BUFFER_SIZE] = { 0 };
    fgets(buffer, MAX_LINE_BUFFER_SIZE, rgsFile);
    if (buffer[0] == '#')
    {
    int controlId = 0;
    int propertyId = 0;
    unsigned int propertyValue = 0;
    while (!feof(rgsFile))
    {
    switch (buffer[0])
    {
    case 'p':
    {
    // Style property: p <control_id> <property_id> <property_value> <property_name>
    sscanf(buffer, "p %d %d 0x%x", &controlId, &propertyId, &propertyValue);
    GuiSetStyle(controlId, propertyId, (int)propertyValue);
    } break;
    case 'f':
    {
    // Style font: f <gen_font_size> <charmap_file> <font_file>
    int fontSize = 0;
    char charmapFileName[256] = { 0 };
    char fontFileName[256] = { 0 };
    sscanf(buffer, "f %d %s %[^\r\n]s", &fontSize, charmapFileName, fontFileName);
    Font font = { 0 };
    int *codepoints = NULL;
    int codepointCount = 0;
    if (charmapFileName[0] != '0')
    {
    // Load text data from file
    // NOTE: Expected an UTF-8 array of codepoints, no separation
    char *textData = LoadFileText(TextFormat("%s/%s", GetDirectoryPath(fileName), charmapFileName));
    codepoints = LoadCodepoints(textData, &codepointCount);
    UnloadFileText(textData);
    }
    if (fontFileName[0] != '\0')
    {
    // In case a font is already loaded and it is not default internal font, unload it
    if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture);
    if (codepointCount > 0) font = LoadFontEx(TextFormat("%s/%s", GetDirectoryPath(fileName), fontFileName), fontSize, codepoints, codepointCount);
    else font = LoadFontEx(TextFormat("%s/%s", GetDirectoryPath(fileName), fontFileName), fontSize, NULL, 0); // Default to 95 standard codepoints
    }
    // If font texture not properly loaded, revert to default font and size/spacing
    if (font.texture.id == 0)
    {
    font = GetFontDefault();
    GuiSetStyle(DEFAULT, TEXT_SIZE, 10);
    GuiSetStyle(DEFAULT, TEXT_SPACING, 1);
    }
    UnloadCodepoints(codepoints);
    if ((font.texture.id > 0) && (font.glyphCount > 0)) GuiSetFont(font);
    } break;
    default: break;
    }
    fgets(buffer, MAX_LINE_BUFFER_SIZE, rgsFile);
    }
    }
    else tryBinary = true;
    fclose(rgsFile);
    }
    if (tryBinary)
    {
    rgsFile = fopen(fileName, "rb");
    if (rgsFile != NULL)
    {
    fseek(rgsFile, 0, SEEK_END);
    int fileDataSize = ftell(rgsFile);
    fseek(rgsFile, 0, SEEK_SET);
    if (fileDataSize > 0)
    {
    unsigned char *fileData = (unsigned char *)RAYGUI_CALLOC(fileDataSize, sizeof(unsigned char));
    if (fileData != NULL)
    {
    fread(fileData, sizeof(unsigned char), fileDataSize, rgsFile);
    GuiLoadStyleFromMemory(fileData, fileDataSize);

While it seems that the body of GuiLoadStyleFromMemory has some hints

  • raygui/src/raygui.h

    Lines 4890 to 4892 in 6d2b28f

    // Font loading is highly dependant on raylib API to load font data and image
    #if !defined(RAYGUI_STANDALONE)

about its implementation being highly dependant on raylib, this does not change the fact that the same code section can be reached publicly with the FromFile method.

This limitation ultimately limits the ability to embed styles in programs using raygui.

Switching between theme definitions obtained from embedding the style files requires some funny code to:

  • Write a temporary file from the already-in-static-memory bytes
  • Load it with the file API
  • Delete the temp file (or not)

Which is prone to error and arguably just worse than exposing the existing, and ultimately already used (same-control-flow-reachable), GuiLoadStyleFromMemory.

Usecase

I have prepared a draft PR for my usecase, involving the rust bindings.

Proposed solutions

I don't really see a real drawback to exposing the function since the same logic is reachable with the GuiLoadStyleFromFile() method.
As a side note, it seems that currently the dataSize argument is not used.

If the function is deemed "unsafe" for some reason, I would like at least a specific build flag to turn a macro guard on an expose it...

But ultimately, having this API just available, without jumping through hoops (for no better or worse guarantees), would be better.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions