Module:Tincture
Comment: There seems to have been a communication failure.
When the minus sign for 'do not categorize' is specified, it means not only
that the error category is suppressed, it means that no categorization at all should occur.
The possibilities are:
- automatic categorization
- categorization as with "cat=..."
- suppress the (automatic) categorization
- and the (automatic) error categorization,
either with "cat=-" or a minus sign like a color code
Done now fixed -- sarang♥사랑 16:48, 13 August 2020 (UTC)
GPL palettes
In August 2020 a substantial expansion occurred, to generate the GPL palettes, wished by users for heraldry works. A new (automatic and optional) Tincture-parameter 'gpltab=' is used to control whether tincture boxes are generated for files, or table data is generated for GPL. Conversion functions care for hexadecimal/decimal conversion as needed for gpl, and additional parameters are passed to the subtemplates. The palettes are generated on the page Commons:Colour palettes and detailled instructions for maintenance and usage are provided.
local p = {} -- Tincture
-------------- locals
local function draw(color, ss, tc, pf, gt)
return mw.getCurrentFrame():expandTemplate{ title = 'Tincture/draw' .. ss, args = { color, gt, tc = tc, pf = pf } }
end -- local function draw
--
local function sortc ( itab, otab, ccode )
for i, v in ipairs(itab) do
if v == ccode then
table.insert(otab, v)
return true
end
end
return false
end -- local function sortc
--
local function category(colors, ss, tc, cat, no_error_cat)
return mw.getCurrentFrame():expandTemplate{ title = 'Tincture/cat' .. ss, args = { table.concat(colors, '/'), tc = tc, cat = cat, ['no error cat'] = no_error_cat and '1' or nil } }
end -- local function category
-- local function: converts 'ddd ddd ddd' to '#rrggbb' (or '#rgb')
local function convdh ( p1, p2, p3 )
local lpar = {}; -- separated by either pipe, slash, minus, comma or space
local dect = {}
local hext = {}
local numb = {}
local same = true
lpar [1] = mw.text.trim ( p1 );
if p3 == nil then -- split-pattern: REGEXP won't work
if p2 ~= nil then
lpar[1] = lpar[1] .. '-' .. mw.text.trim(p2)
end
lpar[1] = mw.ustring.gsub (lpar[1], '-', '/', 3)
lpar[1] = mw.ustring.gsub (lpar[1], ',', '/', 3)
lpar[1] = mw.ustring.gsub (lpar[1], ' ', '/', 3)
dect = mw.text.split(lpar[1] or '1/2/3', '/');
else
lpar [2] = mw.text.trim ( p2 );
lpar [3] = mw.text.trim ( p3 );
dect = lpar;
end
for i = 1, 3 do
numb[i] = tonumber( dect[i] )
if numb[i] == nil or numb[i] > 255 then
error (i .. 'value "' .. dect[i] or '?' .. '" cannot be converted to hexadecimal')
-- ..dect[1]..','..dect[2]..','..dect[3]..'.'..i)
end
hext [i] = mw.ustring.format ( "%X", numb[i] )
if numb[i] < 16 then hext[i] = '0' .. hext[i] end;
if mw.ustring.byte ( hext [i], 1 ) ~= mw.ustring.byte ( hext[i], 2 ) then
same = false
end
end
if same then
hext[1] = mw.ustring.sub (hext[1], 2)
hext[2] = mw.ustring.sub (hext[2], 2)
hext[3] = mw.ustring.sub (hext[3], 2)
end
return '#'..hext[1]..hext[2]..hext[3]
end -- local function convdh
-------------------- local / global ----------``-------------------------------
-- local / global function: converts h → d: #rrggbb or #rgb to table {rr, gg, bb}
function p.convht ( frame )
local gpar = {};
local hexv = nil;
local hexi = '000';
local hwxt = '0';
local gpar = frame.args;
if gpar then
hexv = tostring (gpar[1]); -- global
else
hexv = tostring ( frame ); -- local
end
hexv = mw.text.trim( hexv )
if mw.ustring.sub ( hexv, 1, 1 ) == '#' then
hexi = mw.ustring.sub (hexv, 2)
hext = '1'
elseif mw.ustring.sub ( hexv, 1, 3) == '\\35' then
hexi = mw.ustring.sub (hexv, 4)
hext = '2'
elseif mw.ustring.sub ( hexv, 1, 5) == '#' then
hexi = mw.ustring.sub (hexv, 6)
hext = '3'
elseif mw.ustring.sub ( hexv, 1, 6) == '#' then
hexi = mw.ustring.sub (hexv, 7)
hext = '4'
elseif mw.ustring.sub ( hexv, 1, 6) == '#' then
hexi = mw.ustring.sub (hexv, 7, #hexv)
hext = '5'
elseif mw.ustring.sub ( hexv, 1, 7) == '#' then
hexi = mw.ustring.sub (hexv, 8, #hexv)
hext = '6'
else
hext = '9'
error ('value "' .. hexv .. '" cannot be converted to decimal ' .. #hexv )
end
if #hexi ~= 3 and #hexi ~= 6 then
error ('value "' .. hexi .. '" with length ' .. #hexi .. ' are invalid' )
end
-- error ('value "' .. hexv .. '" type ' .. hext .. ' = ' .. hexi)
local dec = {};
for i = 1, 3 do
if #hexi == 3 then
dec [i] = tonumber ( mw.ustring.sub (hexi, i, i)..mw.ustring.sub (hexi, i, i), 16 )
else
dec [i] = tonumber ( mw.ustring.sub (hexi, 2*i - 1, 2*i), 16 )
end
end
return dec;
end -- function convht
-- local / global function: converts h ← d '#rrggbb' or '#rgb' and returns 'ddd ddd ddd'
function p.convhd ( frame )
local gpar = frame.args;
if gpar then decval = p.convht (gpar[1]); -- global
else decval = p.convht ( frame ); -- local
end
return decval[1]..' '..decval[2]..' '..decval[3]
end -- function convhd
-- local / global function: converts h → d'#rrggbb' or '#rgb' and returns 'ddd ddd ddd' formatted
function p.convhdf ( frame )
local gpar = frame.args;
if gpar then dtab = p.convht (gpar[1]); -- global
else dtab = p.convht ( frame ); -- local
end
local dtxt = ' '
for i = 1, 3 do
if dtab[i] < 100 then
if dtab[i] < 10 then
dtxt = dtxt .. ' '
end
dtxt = dtxt .. ' '
end
dtxt = dtxt .. ' ' .. tostring ( dtab [i] )
end
local contrast = '0';
if dtab [1] + dtab [2] + dtab [3] < 400 then
contrast = 'F';
end
-- TEST ----------
-- local contval = dtab [1] + dtab [2] + dtab [3]
-- contrast = contrast .. ' - ';
-- if contval < 100 then
-- if contval < 10 then
-- contrast = contrast .. ' '
-- end
-- contrast = contrast .. ' '
-- end
-- contrast = contrast .. tostring ( contval );
-- TEST ----------
dtxt = contrast .. dtxt;
return dtxt
end -- function convhdf
-- function returns contrast color
function p.titcolor ( frame )
local gpar = frame.args
local decval = p.convhdf ( gpar[1] );
if mw.ustring.sub ( decval, 1, 1 ) == 'F'
then return 'FFF'
else return '000'
end
end -- function titcolor
-- global function convgpl: gets #rgb, contrast, name; returns line formatted
function p.convgpl ( frame )
local gpar = frame.args;
local line = p.convhdf ( gpar [1] ); -- convert #rgb
local expl = mw.ustring.sub ( line, 2) .. ' ' .. gpar [1]; -- d d d #rgb
if #gpar[1] == 4 then
expl = expl .. ' '
end
local contrast = gpar [2] or '#001'
-- expl = expl .. ' ' .. contrast; -- contrast -test
if mw.ustring.sub ( contrast, 2, 2) == mw.ustring.sub ( line, 1, 1)
then expl = expl .. '<tt> </tt>'
else expl = expl .. '<tt>·</tt>'
end
expl = expl .. gpar [3]; -- name
return expl
end -- function convgpl
-- global function convert: gets 3 num, returns hex and dec formatted
function p.convert ( frame )
local gpar = frame.args;
local hcod = convdh ( gpar[1], gpar[2], gpar[3] );
local fnum = p.convhdf (hcod)
return '#' .. mw.ustring.sub ( hcod, 2 ) .. mw.ustring.sub ( fnum, 2);
end -- function convert
-- ============================================================================
-- main function tincture
function p.main (frame)
local getArgs = require( 'Module:Arguments' ).getArgs
local args = getArgs(frame)
local ss = args.ss or '0'
if ss == '≈' then ss = '0' end
local tc = args.tc
local pf = args.pf
local gt = args.gpltab or ""
local align = 'tincturebox-left'
local error_cat = true
local InFi = (args['+'] == '+')
local cols = args
local colors = {}
local box = {}
local tab = {}
local out = {}
local ordtab = { }
local insert = false
if gt == "" then
if mw.title.getCurrentTitle().namespace == 4 then gt = '3'
else gt = '1'
end
end
if gt == "2" or gt == "3" then
InFi = true
error_cat = false
end
ss = mw.ustring.upper( ss )
if type(args[1]) == 'string' and args[1]:sub(1, 6) == '<table' then
return args[1]
end
if args[2] == nil then
cols = mw.text.split(args[1] or '', '%s*/%s*')
end
if cols.ss then
ss = mw.ustring.upper( cols.ss )
end
for _, v in ipairs(cols) do
if not v or v == '' then
break
elseif v == '-' then
error_cat = false
elseif v == '+' then
InFi = true
elseif mw.ustring.sub( v, 1, 3 ) == 'ss=' then -- any case when ss=
ss = mw.ustring.upper( mw.ustring.sub( v, 4 ) )
elseif mw.ustring.len( v ) == 2
and v == mw.ustring.upper( v ) then -- belongs to character class %u
ss = v
else
table.insert(colors, v)
end
end
-- 0) headline and boxes
if gt == "2" or gt =="3" then
table.insert(out, frame:expandTemplate{title='=', args={'<h4>GPLtab '..draw('gpltabnam',ss,'','','tab')..'</h4>'}})
end
for i, v in ipairs(colors) do
box[i] = draw(v, ss, tc, pf, 'box')
end
-- 1) cat: sorted table
if error_cat == true then
insort = sortc (colors, ordtab, 'a' )
insort = sortc (colors, ordtab, 'A' )
insort = sortc (colors, ordtab, 'o' )
insort = sortc (colors, ordtab, 'b' )
insort = sortc (colors, ordtab, 'B' )
insort = sortc (colors, ordtab, 'c' )
insort = sortc (colors, ordtab, 'C' )
insort = sortc (colors, ordtab, 'g' )
insort = sortc (colors, ordtab, 'n' )
insort = sortc (colors, ordtab, 'p' )
insort = sortc (colors, ordtab, 's' )
insort = sortc (colors, ordtab, 't' )
insort = sortc (colors, ordtab, 'v' )
insort = sortc (colors, ordtab, 'x' )
table.insert(box, category(ordtab, ss, tc, args.cat, no_error_cat))
end
-- 2) box
if gt == "1" or gt =="3" then
if args.align == 'right' or args.align == 'center' then
align = 'tincturebox-' .. align
end
local frame = mw.getCurrentFrame()
text = frame:extensionTag('templatestyles', '', { src = 'Tincture/styles.css' }) ..
'<div class="tincturebox ' .. align .. '">' .. table.concat(box) .. '</div>'
if InFi then
local name = mw.getContentLanguage():ucfirst(frame:expandTemplate{ title = 'I18n/COA', args = { 'tincture' } })
local link = ' ([[Template:Tincture/draw'..ss..'|'..ss..']])'
if ss ~= '' and ss ~= '0' then name = name .. link end
table.insert(out, frame:expandTemplate{ title = 'InFi', args = { name, text } })
else
table.insert(out, text )
end
end
-- 3) tab
if gt == "2" or gt =="3" then
table.insert(out, frame:expandTemplate{ title = '=', args = { "#<br>" } })
for i, v in ipairs(colors) do
table.insert(out, draw( v, ss, tc, pf, 'tab') )
end
table.insert(out, frame:expandTemplate{ title = '=', args = { "<br><br>" } })
end
return table.concat(out)
end -- function main / tincture
return p;