Editing Module:ItemBoxGive feedback
Jump to navigation
Jump to search
The edit can be undone.
Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.
| Latest revision | Your text | ||
| Line 1: | Line 1: | ||
local p = {} | local p = {} | ||
local ustring = mw.ustring | local ustring = mw.ustring | ||
-- ============================================================================ | -- ============================================================================ | ||
-- | -- Retail Demo (bold) glyph advance widths, in em of the font size. | ||
-- | -- unitsPerEm = 1000. Measured 2026-07-20 with fontTools from | ||
-- | -- File:Retaildemo-bold.woff2 ( /images/d/d5/Retaildemo-bold.woff2 ), | ||
-- | -- the bold face used by .modName. | ||
-- | -- | ||
-- | -- THIS TABLE IS FONT-SPECIFIC. If that file is re-uploaded with different | ||
-- | -- metrics, name fitting will drift; regenerate the table from the new file's | ||
-- | -- hmtx / unitsPerEm. | ||
-- ============================================================================ | -- ============================================================================ | ||
local | local WIDTH = { | ||
A=0.677, B=0.590, C=0.621, D=0.693, E=0.552, F=0.530, G=0.686, H=0.702, | |||
I=0.276, J=0.301, K=0.637, L=0.491, M=0.904, N=0.695, O=0.741, P=0.585, | |||
Q=0.740, R=0.628, S=0.555, T=0.555, U=0.694, V=0.668, W=0.913, X=0.667, | |||
Y=0.635, Z=0.666, | |||
a=0.573, b=0.608, c=0.473, d=0.604, e=0.570, f=0.382, g=0.558, h=0.608, | |||
i=0.269, j=0.266, k=0.584, l=0.268, m=0.907, n=0.602, o=0.611, p=0.604, | |||
q=0.605, r=0.392, s=0.496, t=0.404, u=0.602, v=0.549, w=0.776, x=0.571, | |||
y=0.550, z=0.561, | |||
["0"]=0.662, ["1"]=0.312, ["2"]=0.560, ["3"]=0.566, ["4"]=0.612, | |||
["5"]=0.562, ["6"]=0.601, ["7"]=0.520, ["8"]=0.583, ["9"]=0.598, | |||
[" "]=0.240, | |||
} | |||
-- | -- Characters absent from Retail Demo (hyphen, apostrophe, ...) are drawn by the | ||
-- . | -- browser in the fallback sans-serif; this is a reasonable stand-in width. | ||
local FALLBACK = 0.60 | |||
-- Card geometry in px at the reference scale where 1em = 10px. The card is | |||
-- scaled through font-size on .CitadelShopMod (the |size= parameter) and the | |||
-- value returned here is em, so it scales together with everything else. | |||
local USABLE_W = 72 -- 80px card minus 4px padding on each side | |||
local NAME_H = 42 -- vertical room the wrapped name may occupy | |||
local LINE_H = 1.2 -- must match .modName line-height | |||
local MAX_PX = 15 -- full size (1.50em) | |||
local MIN_PX = 8 -- hard floor (0.80em) | |||
local function charWidth(ch) | |||
local w = WIDTH[ch] | |||
if w then return w end | |||
local cp = ustring.codepoint(ch) or 0 | |||
-- CJK / full-width ranges render roughly twice as wide as Latin | |||
if (cp >= 0x1100 and cp <= 0x115F) or (cp >= 0x2E80 and cp <= 0xA4CF) | |||
or (cp >= 0xAC00 and cp <= 0xD7A3) or (cp >= 0xF900 and cp <= 0xFAFF) | |||
or (cp >= 0xFF00 and cp <= 0xFF60) or (cp >= 0xFFE0 and cp <= 0xFFE6) then | |||
return 2.0 | |||
end | |||
return FALLBACK | |||
end | |||
local function wordWidth(word) | |||
local total = 0 | |||
for ch in ustring.gmatch(word, ".") do | |||
total = total + charWidth(ch) | |||
end | |||
return total | |||
end | |||
-- Greedy line count when filling USABLE_W at font size `px`. Close enough to | |||
-- text-wrap:balance for sizing, since both keep every word intact. | |||
local function lineCount(words, px) | |||
local space = charWidth(" ") * px | |||
local cur, lines = 0, 1 | |||
for _, w in ipairs(words) do | |||
local ww = wordWidth(w) * px | |||
if cur == 0 then | |||
cur = ww | |||
elseif cur + space + ww <= USABLE_W then | |||
cur = cur + space + ww | |||
else | |||
lines = lines + 1 | |||
cur = ww | |||
end | |||
end | |||
return lines | |||
end | |||
-- Returns the name font size as an em string (scales with the card). | |||
function p.getFontSize(frame) | function p.getFontSize(frame) | ||
local name = ustring.gsub(frame.args[1] or "", "^%s*(.-)%s*$", "%1") | local name = ustring.gsub(frame.args[1] or "", "^%s*(.-)%s*$", "%1") | ||
if name == "" then return string.format("%.2f", MAX_PX / 10) end | |||
if name == "" then return string.format("%. | |||
local words = {} | |||
for w in ustring.gmatch(name, "%S+") do words[#words + 1] = w end | |||
local widest = 0 | |||
for _, w in ipairs(words) do | |||
local ww = wordWidth(w) | |||
end | if ww > widest then widest = ww end | ||
end | |||
local px = USABLE_W / widest | |||
if px > MAX_PX then px = MAX_PX end | |||
while px > MIN_PX and lineCount(words, px) * LINE_H * px > NAME_H do | |||
px = px - 0.25 | |||
end | |||
if px < MIN_PX then px = MIN_PX end | |||
local snapped = math.floor(px * 2 + 0.5) / 2 | |||
local | if lineCount(words, snapped) * LINE_H * snapped > NAME_H then | ||
snapped = math.floor(px * 2) / 2 | |||
end | end | ||
return string.format("%.2f", snapped / 10) | |||
return string.format(" | |||
end | end | ||
return p | return p | ||