-- Added new accessibility module -- Added multiple colour convert functions (rgb to hex, rgb to hsl, hsl to rgb, hex to rgb) -- Added adjusment function for colours -- Added check for colourbliness alteration -- Added colourblindness command uses `accessibility.cb_command` as command string -- Added menu option to change colourblind options. -- Added multiple accessibility locale enteries within en.json -- Added multiple accessibility locale enteries within pt.json (translated via google translate) -- Fixed disabled not showing up when using qb-menu. -- Updated init.lua and fxmanifest.lua to include new module entry
210 lines
8.0 KiB
Lua
210 lines
8.0 KiB
Lua
local colourblind = GetResourceKvpString('colourblind') or "default"
|
|
local QB = false
|
|
if (BridgeClientConfig.MenuSystem == "auto" and GetResourceState("qb-menu") ~= "started") or (BridgeClientConfig.MenuSystem ~= "auto" and BridgeClientConfig.MenuSystem == "qb-menu") then
|
|
QB = true
|
|
end
|
|
|
|
Accessibility = Accessibility or {}
|
|
|
|
RegisterCommand(locale("accessibility.cb_command"), function()
|
|
Accessibility.updatecolourblindness()
|
|
end, false)
|
|
|
|
Accessibility.updatecolourblindness = function()
|
|
local currentCB = locale("accessibility.cb_"..colourblind.."_title")
|
|
local cbIcon = "fas fa-eye-low-vision"
|
|
Menu.Open({
|
|
id = 'colourblind_update',
|
|
title = locale("accessibility.cb_title"),
|
|
options = {
|
|
{
|
|
title = locale("accessibility.cb_title"),
|
|
description = locale("accessibility.cb_desc"):format(currentCB),
|
|
disabled = true,
|
|
},
|
|
{
|
|
title = locale("accessibility.cb_default_title"),
|
|
description = locale("accessibility.cb_default_desc"),
|
|
icon = "fas fa-eye",
|
|
onSelect = function()
|
|
colourblind = "default"
|
|
SetResourceKvp('colourblind', colourblind)
|
|
Notify.SendNotify(locale("accessibility.cb_updated"):format(locale("accessibility.cb_"..colourblind.."_title")), 'success', 3000)
|
|
end
|
|
},
|
|
{
|
|
title = locale("accessibility.cb_protanomaly_title"),
|
|
description = locale("accessibility.cb_protanomaly_desc"),
|
|
icon = cbIcon,
|
|
onSelect = function()
|
|
colourblind = "protanomaly"
|
|
SetResourceKvp('colourblind', colourblind)
|
|
Notify.SendNotify(locale("accessibility.cb_updated"):format(locale("accessibility.cb_"..colourblind.."_title")), 'success', 3000)
|
|
end
|
|
},
|
|
{
|
|
title = locale("accessibility.cb_deuteranomaly_title"),
|
|
description = locale("accessibility.cb_deuteranomaly_desc"),
|
|
icon = cbIcon,
|
|
onSelect = function()
|
|
colourblind = "deuteranomaly"
|
|
SetResourceKvp('colourblind', colourblind)
|
|
Notify.SendNotify(locale("accessibility.cb_updated"):format(locale("accessibility.cb_"..colourblind.."_title")), 'success', 3000)
|
|
end
|
|
},
|
|
{
|
|
title = locale('accessibility.cb_dual_title'),
|
|
description = locale("accessibility.cb_dual_desc"),
|
|
icon = cbIcon,
|
|
onSelect = function()
|
|
colourblind = "dual"
|
|
SetResourceKvp('colourblind', colourblind)
|
|
Notify.SendNotify(locale("accessibility.cb_updated"):format(locale("accessibility.cb_"..colourblind.."_title")), 'success', 3000)
|
|
end
|
|
},
|
|
{
|
|
title = locale("accessibility.cb_tritanopia_title"),
|
|
description = locale("accessibility.cb_tritanopia_desc"),
|
|
icon = cbIcon,
|
|
onSelect = function()
|
|
colourblind = "tritanopia"
|
|
SetResourceKvp('colourblind', colourblind)
|
|
Notify.SendNotify(locale("accessibility.cb_updated"):format(locale("accessibility.cb_"..colourblind.."_title")), 'success', 3000)
|
|
end
|
|
},
|
|
{
|
|
title = locale("accessibility.cb_tritanomaly_title"),
|
|
description = locale("accessibility.cb_tritanomaly_desc"),
|
|
icon = cbIcon,
|
|
onSelect = function()
|
|
colourblind = "tritanomaly"
|
|
SetResourceKvp('colourblind', colourblind)
|
|
Notify.SendNotify(locale("accessibility.cb_updated"):format(locale("accessibility.cb_"..colourblind.."_title")), 'success', 3000)
|
|
end
|
|
},
|
|
}},QB)
|
|
end
|
|
Accessibility.hexToRgb = function(hex)
|
|
hex = hex:gsub("#", "")
|
|
local r,g,b = tonumber("0x" .. hex:sub(1, 2)),tonumber("0x" .. hex:sub(3, 4)),tonumber("0x" .. hex:sub(5, 6))
|
|
return r, g, b
|
|
end
|
|
|
|
Accessibility.rgbToHex = function(r, g, b)
|
|
return string.format("#%02x%02x%02x", r, g, b)
|
|
end
|
|
|
|
Accessibility.rgbToHsl = function(r, g, b)
|
|
r = r / 255
|
|
g = g / 255
|
|
b = b / 255
|
|
local max = math.max(r, g, b)
|
|
local min = math.min(r, g, b)
|
|
local h, s, l = 0, 0, (max + min) / 2
|
|
|
|
if max == min then
|
|
h, s = 0, 0 -- achromatic
|
|
else
|
|
local d = max - min
|
|
s = l > 0.5 and d / (2 - max - min) or d / (max + min)
|
|
if max == r then
|
|
h = (g - b) / d + (g < b and 6 or 0)
|
|
elseif max == g then
|
|
h = (b - r) / d + 2
|
|
elseif max == b then
|
|
h = (r - g) / d + 4
|
|
end
|
|
h = h / 6
|
|
end
|
|
return h, s, l
|
|
end
|
|
|
|
Accessibility.hslToRgb = function(h, s, l)
|
|
local r, g, b
|
|
if s == 0 then
|
|
r, g, b = l, l, l -- achromatic
|
|
else
|
|
local function hue2rgb(p, q, t)
|
|
if t < 0 then t = t + 1 end
|
|
if t > 1 then t = t - 1 end
|
|
if t < 1 / 6 then return p + (q - p) * 6 * t end
|
|
if t < 1 / 2 then return q end
|
|
if t < 2 / 3 then return p + (q - p) * (2 / 3 - t) * 6 end
|
|
return p
|
|
end
|
|
|
|
local q = l < 0.5 and l * (1 + s) or l + s - l * s
|
|
local p = 2 * l - q
|
|
r = hue2rgb(p, q, h + 1 / 3)
|
|
g = hue2rgb(p, q, h)
|
|
b = hue2rgb(p, q, h - 1 / 3)
|
|
end
|
|
return math.floor(r * 255), math.floor(g * 255), math.floor(b * 255)
|
|
end
|
|
|
|
Accessibility.adjustColourForColourblindness = function(num, returnAsRGB)
|
|
local r, g, b
|
|
if type(num) ~= "table" and num:match("^#%x%x%x%x%x%x$") then
|
|
r, g, b = Accessibility.hexToRgb(num) -- Convert hex to RGB
|
|
else
|
|
r, g, b = num.r, num.g, num.b -- If it's already RGB, use it directly
|
|
end
|
|
local h, s, l = Accessibility.rgbToHsl(r, g, b) -- Convert RGB to HSL
|
|
-- Adjust hue values based on colourblindness type
|
|
if colourblind == "protanomaly" then -- Red-blind
|
|
-- Shift towards blue/cyan
|
|
h = (h + 0.5) % 1 -- Shift by 180 degrees
|
|
elseif colourblind == "deuteranomaly" then -- Green-blind
|
|
-- Shift towards blue/magenta
|
|
h = (h + 0.33) % 1 -- Shift by 120 degrees
|
|
elseif colourblind == "dual" then -- Protanopia and Deuteranopia (Red-Green blind)
|
|
-- More significant shift towards blue/yellow
|
|
-- This is a more drastic shift to maximize contrast
|
|
if h < 0.166 then -- Reddish hues
|
|
h = 0.66 -- Shift to blue
|
|
elseif h < 0.5 then -- Greenish hues
|
|
h = 0.166 -- Shift to yellow
|
|
else
|
|
h = h -- Leave blue/purple hues alone
|
|
end
|
|
-- Increase saturation and lightness to make colours more distinct
|
|
s = math.min(s * 1.5, 1)
|
|
l = math.min(l * 1.2, 1)
|
|
elseif colourblind == "tritanopia" then -- Blue-blind
|
|
-- Shift towards red/yellow
|
|
h = (h + 0.16) % 1 -- Shift by 60 degrees
|
|
elseif colourblind == "tritanomaly" then
|
|
h = (h + 0.08) % 1
|
|
end
|
|
|
|
-- Convert back to RGB
|
|
r, g, b = Accessibility.hslToRgb(h, s, l)
|
|
if returnAsRGB then
|
|
return {r = r, g = g, b = b}
|
|
else
|
|
-- Convert back to HEX
|
|
local newHex = Accessibility.rgbToHex(r, g, b)
|
|
return newHex
|
|
end
|
|
end
|
|
|
|
---@returns a colour adjusted for colourblindness in HEX if variable `returnAsRGB` is false
|
|
---@param colourName string Colour name in HEX format or RGB format
|
|
-- This is the trigger function for altering colours for colourblindness :D
|
|
Accessibility.getAdjustedColour = function(colourName, returnAsRGB)
|
|
local originalHex = colourName
|
|
if originalHex then
|
|
if colourblind == "default" then
|
|
if type(colourName) == "table" and not returnAsRGB then
|
|
return Accessibility.rgbToHex(colourName.r, colourName.g, colourName.b)
|
|
else
|
|
return originalHex
|
|
end
|
|
else
|
|
return Accessibility.adjustColourForColourblindness(originalHex, returnAsRGB)
|
|
end
|
|
else
|
|
Prints.Error("Invalid Colour Name^0] [^3"..colourName.."^0")
|
|
return "#FFFFFF" -- Default to white if the colour name is invalid
|
|
end
|
|
end |