Skip to content

Add support for per-element RGB color code toggling in GUI elements#4961

Open
TheCrazy17 wants to merge 3 commits into
multitheftauto:masterfrom
TheCrazy17:feat/gui-rgb-color-codes
Open

Add support for per-element RGB color code toggling in GUI elements#4961
TheCrazy17 wants to merge 3 commits into
multitheftauto:masterfrom
TheCrazy17:feat/gui-rgb-color-codes

Conversation

@TheCrazy17

Copy link
Copy Markdown
Contributor

Summary

Added RGB color code support for GUI elements, allowing inline color formatting across all supported GUI controls.

guiSetColorCodesEnabled(guiElement, enabled [, includeChilds = false])

When includeChilds is true, the function recursively applies the color code state to all child GUI elements, making it easy to enable or disable RGB color codes for an entire GUI hierarchy with a single call.

Screenshots
mta-screen_2026-06-18_23-31-01 mta-screen_2026-06-18_23-31-16 mta-screen_2026-06-18_23-31-24

Motivation

Finally, RGB color codes are supported in MTA GUI elements.

This change adds consistent inline color formatting across GUI components such as windows, labels, buttons, checkboxes, radio buttons, tabs, grid lists (headers and rows), edit boxes, memos, combo boxes, and title bars.

Closes #4433.

Test plan

Tested client-side using the following script to verify that all supported GUI elements correctly render RGB color codes and update immediately when color codes are enabled or disabled recursively.

-- Client-side test script for MTA GUI RGB color codes.
-- Use the /testrgb command in the game chat to open or close the test window.

local demoWindow = nil
local colorCodesState = true

local function buildTestGUI()
    -- 1. Window & Titlebar
    demoWindow = guiCreateWindow(100, 100, 600, 450, "#FF0000M#00FF00T#0000FFA #FFFFFFColor Code Test Window", false)
    guiWindowSetSizable(demoWindow, true)

    -- 2. Label
    guiCreateLabel(20, 40, 560, 20, "Label: #FF3333R#33FF33G#3333FFB inline coloring #FFAA00Orange #00FFFFCyan", false, demoWindow)

    -- 3. Button
    guiCreateButton(20, 70, 150, 30, "#FF5555Click #55FF55Me", false, demoWindow)

    -- 4. CheckBox
    guiCreateCheckBox(190, 70, 150, 30, "#FFFF00Checked #FF00FFBox", true, false, demoWindow)

    -- 5. Radio Button
    guiCreateRadioButton(360, 70, 180, 30, "#00FFFFRadio #FFFFFFButton", false, demoWindow)

    -- 6. Tab Panel & Tabs
    local tabPanel = guiCreateTabPanel(20, 110, 560, 200, false, demoWindow)
    local tab1 = guiCreateTab("#FF5555Tab #55FF55One", tabPanel)
    local tab2 = guiCreateTab("#5555FFTab #FFFF55Two", tabPanel)

    -- 7. GridList (Rows & Headers)
    local gridList = guiCreateGridList(10, 10, 540, 150, false, tab1)
    local col1 = guiGridListAddColumn(gridList, "#FFAA00Column #FF00FFOne", 0.4)
    local col2 = guiGridListAddColumn(gridList, "#00FFAAColumn #00FFFFTwo", 0.5)

    for i = 1, 3 do
        local row = guiGridListAddRow(gridList)
        guiGridListSetItemText(gridList, row, col1, "#FF5555Row " .. i .. " #FFFFFFCol 1", false, false)
        guiGridListSetItemText(gridList, row, col2, "#55FF55Row " .. i .. " #FFFF55Col 2", false, false)
    end

    -- 8. Memo
    guiCreateMemo(10, 10, 260, 100, "Memo: #FF8888Line 1\n#88FF88Line 2\n#8888FFLine 3", false, tab2)

    -- 9. Edit
    guiCreateEdit(10, 120, 260, 30, "Edit: #FFBB00Yellow", false, tab2)

    -- 10. ComboBox
    local comboBox = guiCreateComboBox(280, 10, 260, 140, "#FFFFFFSelect #FF00FFan #00FFFFitem", false, tab2)
    guiComboBoxAddItem(comboBox, "#FF5555Red Item")
    guiComboBoxAddItem(comboBox, "#55FF55Green Item")
    guiComboBoxAddItem(comboBox, "#5555FFBlue Item")

    -- Toggle button
    local toggleBtn = guiCreateButton(20, 320, 560, 40, "TOGGLE COLOR CODES (Currently: ON)", false, demoWindow)

    -- Close button
    local closeBtn = guiCreateButton(20, 370, 560, 30, "CLOSE TEST WINDOW", false, demoWindow)

    local function applyColorCodesState()
        guiSetColorCodesEnabled(demoWindow, colorCodesState, true)

        guiSetText(
            toggleBtn,
            "TOGGLE COLOR CODES (Currently: " ..
                (colorCodesState and "#00FF00ON" or "#FF0000OFF") .. ")"
        )

        -- Keep the toggle button itself colored.
        guiSetColorCodesEnabled(toggleBtn, true)
    end

    applyColorCodesState()

    addEventHandler("onClientGUIClick", toggleBtn, function(btn, state)
        if btn == "left" and state == "up" then
            colorCodesState = not colorCodesState
            applyColorCodesState()
        end
    end, false)

    addEventHandler("onClientGUIClick", closeBtn, function(btn, state)
        if btn == "left" and state == "up" then
            destroyElement(demoWindow)
            showCursor(false)
        end
    end, false)

    showCursor(true)
end

addCommandHandler("testrgb", function()
    if isElement(demoWindow) then
        destroyElement(demoWindow)
        showCursor(false)
    else
        buildTestGUI()
    end
end)

The test verifies:

  • Window title rendering.
  • Labels.
  • Buttons.
  • Checkboxes.
  • Radio buttons.
  • Tab panel and tab captions.
  • GridList headers and row items.
  • Memo text.
  • Edit box text.
  • ComboBox caption and items.
  • Recursive enable/disable behavior using guiSetColorCodesEnabled(element, enabled, true).
  • Instant visual updates after toggling color codes.

Checklist

  • Your code should follow the coding guidelines.
  • Smaller pull requests are easier to review. If your pull request is beefy, your pull request should be reviewable commit-by-commit.

Implements GH issue multitheftauto#4433. GUI text elements (labels, buttons, edit boxes,
etc.) now parse #RRGGBB sequences as inline color changes. Any '#' not
followed by exactly 6 hex digits is treated as a literal character.

  guiSetText(label, "#FF0000Red #00FF00Green #0000FFBlue")

The alpha of the original widget colour is preserved across color changes.
Color codes are skipped in getTextExtent() and getCharAtPixel() so they
have no visual width and do not affect text layout or cursor positioning.
Both left-aligned (drawTextLine) and justified (drawTextLineJustified)
rendering paths are covered.
Color codes are now OFF by default, preserving full backward compatibility.
Scripts opt in per element:

  guiSetColorCodesEnabled(element, true)   -- enable #RRGGBB parsing
  guiSetColorCodesEnabled(element, false)  -- disable (default)
  guiGetColorCodesEnabled(element)         -- query state
  element.colorCodesEnabled = true         -- OOP style

Implementation: Font::s_colorCodesEnabled (default false) is set inside
Window::drawSelf() from a per-window UserString before populateRenderCache()
is called, then reset to false. This keeps the toggle contained to the
render-cache rebuild phase without touching individual widget types.
Adds \guiSetColorCodesEnabled\, allowing RGB color codes to be toggled on a per-element basis.

- Fixes issues where complex Falagard widgets (Buttons, Checkboxes) ignored color codes.

- Implements inheritance so internal components (Titlebars, TabButtons) respect their parent's setting.

- Adds an optional \includeChildren\ parameter to apply the toggle recursively.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make CEGUI text render hex color parser

1 participant