%D \module %D [ file=meta-imp-segments, %D version=2024.07.31, %D title=\METAPOST\ Graphics, %D subtitle=Segment Numbers, %D author=Hans Hagen, %D date=\currentdate, %D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] %C %C This module is part of the \CONTEXT\ macro||package and is %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. % I made this module for the 2024 \CONTEXT\ meeting in (watertower) Lutten NL for % the math & calculating devices day. Originally I just replaced the regular digits % but then found that we have official \UNICODE\ slot for them. Of course we could % have given all names like \quote {segment } but this is how it evolved. \startluacode local newprivateslot = fonts.helpers.newprivateslot -- We started out with this: for i=10,15 do newprivateslot("segment digit " .. i) -- A .. F end -- and then added a period. -- newprivateslot("segment period") -- but needed some more, so (in \TEX\ speak we have others): newprivateslot("segment other .") newprivateslot("segment other -") newprivateslot("segment other :") -- Just for fun this was also done: newprivateslot("segment letter C") newprivateslot("segment letter O") newprivateslot("segment letter N") newprivateslot("segment letter T") newprivateslot("segment letter E") newprivateslot("segment letter X") -- which alternatively can be done in a loop: -- for chr in string.gmatch("CONTEX") do -- newprivateslot("segment letter " .. chr) -- end ; -- For the cyx 2024 talk I also needed: newprivateslot("segment elements") newprivateslot("segment diagonals") \stopluacode % Next we define the shapes in \METAFUN\ speak, Because the presentation looked % better with a bit bolder elements I added conbrol over the offset, slant an % weight. After all we can pass these as prt of the feature. \startMPcalculation{simplefun} % We should do this a bit more abstract and take the line width into account % but I leave that for now. It just evolved out of a half hour hack for Willi % and Bruce. path segment_glyphs[] ; path segment_snippets[] ; def InitializeSegments = save xoffset ; xoffset := 0.1 ; save yoffset ; yoffset := 0.1 ; save slant ; slant := 0 ; save weight ; weight := 1 ; % xoffset := 0.11 ; % yoffset := 0.11 ; % slant := 0.10 ; % weight := 2.00 ; if hasparameter "mpsfont" "weight" : weight := getparameterdefault "mpsfont" "weight" 1 ; fi ; if hasparameter "mpsfont" "slant" : slant := getparameterdefault "mpsfont" "slant" 0 ; fi ; if hasparameter "mpsfont" "offset" : xoffset := yoffset := getparameterdefault "mpsfont" "offset" 0.1 ; fi ; % The seven segments (not cf the official a-g setup: segment_snippets[1] := (0+xoffset,2) -- (1-xoffset,2) ; segment_snippets[2] := (0,1+yoffset) -- (0,2-yoffset) ; segment_snippets[3] := (1,1+yoffset) -- (1,2-yoffset) ; segment_snippets[4] := (0+xoffset,1) -- (1-xoffset,1) ; segment_snippets[5] := (0,0+yoffset) -- (0,1-yoffset) ; segment_snippets[6] := (1,0+yoffset) -- (1,1-yoffset) ; segment_snippets[7] := (0+xoffset,0) -- (1-xoffset,0) ; % The period: I tried a circle but that loosk pretty bad due to the % small scale. So segment_snippets[20] := (1.30, 0 ) -- (1.30, 0.30) -- (1.40, 0.30) -- (1.40, 0 ) -- cycle ; segment_snippets[21] := (0.45, 0.30) -- (0.45, 0.60) -- (0.55, 0.60) -- (0.55, 0.30) -- cycle ; segment_snippets[22] := (0.45,2-0.30) -- (0.45,2-0.60) -- (0.55,2-0.60) -- (0.55,2-0.30) -- cycle ; % For playing around we have the two possible nine segment diagonals: % segment_snippets[8 ] := (1/2+xoffset/2,1+yoffset) -- (1-xoffset,2-yoffset) ; % segment_snippets[9 ] := (1/2-xoffset/2,1-yoffset) -- (0+xoffset,0+yoffset) ; % segment_snippets[10] := (1/2-xoffset/2,1+yoffset) -- (0+xoffset,2-yoffset) ; % segment_snippets[11] := (1/2+xoffset/2,1-yoffset) -- (1-xoffset,0+yoffset) ; % Somewhat better when bolder: butonly used in talk: segment_snippets[8 ] := (1/2+4xoffset/6,1+8yoffset/6) -- (1-8xoffset/6,2-8yoffset/6) ; segment_snippets[9 ] := (1/2-4xoffset/6,1-8yoffset/6) -- (0+8xoffset/6,0 +8yoffset/6) ; segment_snippets[10] := (1/2-4xoffset/6,1+8yoffset/6) -- (0+8xoffset/6,2 -8yoffset/6) ; segment_snippets[11] := (1/2+4xoffset/6,1-8yoffset/6) -- (1-8xoffset/6,0+8yoffset/6) ; % We can cheat but let's keep that as comment: % segment_snippets[12] := (1/2, 1+yoffset) -- (1/2, 2-yoffset) ; % segment_snippets[13] := (1/2, 1-yoffset) -- (1/2, yoffset) ; % segment_snippets[14] := ( xoffset,2) -- (1/2-xoffset,2) ; % segment_snippets[15] := (1/2+xoffset,2) -- ( 1-xoffset,2) ; % Now we assemble the segments: vardef combine_snippets(text t) = for i=t : segment_snippets[i] && endfor nocycle enddef ; segment_glyphs[ 0] := combine_snippets(1, 2, 3, 5, 6, 7) ; % 0 segment_glyphs[ 1] := combine_snippets( 3, 6 ) ; % 1 segment_glyphs[ 2] := combine_snippets(1, 3, 4, 5, 7) ; % 2 segment_glyphs[ 3] := combine_snippets(1, 3, 4, 6, 7) ; % 3 segment_glyphs[ 4] := combine_snippets( 2, 3, 4, 6 ) ; % 4 segment_glyphs[ 5] := combine_snippets(1, 2, 4, 6, 7) ; % 5 segment_glyphs[ 6] := combine_snippets(1, 2, 4, 5, 6, 7) ; % 6 segment_glyphs[ 7] := combine_snippets(1, 3, 6 ) ; % 7 segment_glyphs[ 8] := combine_snippets(1, 2, 3, 4, 5, 6, 7) ; % 8 segment_glyphs[ 9] := combine_snippets(1, 2, 3, 4, 6, 7) ; % 9 segment_glyphs[10] := combine_snippets(1, 2, 3, 4, 5, 6 ) ; % A segment_glyphs[11] := combine_snippets( 2, 4, 5, 6, 7) ; % B segment_glyphs[12] := combine_snippets(1, 2, 5, 7) ; % C segment_glyphs[13] := combine_snippets( 3, 4, 5, 6, 7) ; % D segment_glyphs[14] := combine_snippets(1, 2, 4, 5, 7) ; % E segment_glyphs[15] := combine_snippets(1, 2, 4, 5 ) ; % F % Sometimes these are used ... but not here; % segment_glyphs[6] := combine_snippets( 2, 4, 5, 6, 7) ; % segment_glyphs[7] := combine_snippets(1, 2, 3, 6 ) ; % segment_glyphs[9] := combine_snippets(1, 2, 3, 4, 6 ) ; % The symbols: segment_glyphs[45] := segment_snippets[4] ; % minus segment_glyphs[46] := segment_snippets[20] ; % period segment_glyphs[58] := combine_snippets(21,22) ; % colon % Some letters: segment_glyphs[67] := combine_snippets(1, 2, 5, 7 ) ; % C % can be different from digit C segment_glyphs[69] := combine_snippets(1, 2, 4, 5, 7 ) ; % E % can be different from digit E segment_glyphs[78] := combine_snippets( 2, 3, 5, 6, 10, 11) ; % N segment_glyphs[79] := combine_snippets(1, 2, 3, 5, 6, 7 ) ; % O % can be different from digit 0 segment_glyphs[84] := combine_snippets( 2, 4, 5, 7, ) ; % T % ugly segment_glyphs[88] := combine_snippets( 8, 9, 10, 11) ; % X % cheat % The \quote {t} is ugly and will remain so, so not: % segment_glyphs[84] := combine_snippets(12, 13, 14, 15) ; % T % also ugly % The used segments positioned relative to each other. In a clock display the % colon is a dedicated thing so it will not be in every segment. In that case % the diagonals can be there. segment_glyphs[100] := combine_snippets(1,2,3,4,5,6,7,20,21,22) ; segment_glyphs[101] := combine_snippets(1,2,3,4,5,6,7,8,9,10,11) ; if slant <> 0 : for i=0 upto 88 : if known segment_glyphs[i] : segment_glyphs[i] := segment_glyphs[i] slanted .1 ; fi ; endfor ; fi ; enddef ; vardef Segment(expr i) = numeric u ; u := 1 ; draw image ( draw segment_glyphs[i] scaled u withpen pencircle scaled (weight*u/7.5) ; ; ) shifted (u/5+u/20,u/20) enddef ; lmt_registerglyphs [ name = "segments", units = 3, usecolor = true, width = 1.5, width = 1.8, height = 2.1, depth = 0, preamble = "InitializeSegments" ] ; % set tounicode for i=0 upto 9 : lmt_registerglyph [ category = "segments", unicode = 130032 + (i mod 10), % 0x1FBF0 .. 0x1FBF9 tounicode = (ASCII "0") + (i mod 10), code = "Segment(" & decimal i & ")", ] ; endfor ; for i=(ASCII "A") upto (ASCII "F") : lmt_registerglyph [ category = "segments", private = "segment digit " & utfchr(i), tounicode = i, code = "Segment(" & decimal (10 + i - ASCII "A") & ")", ] ; endfor ; for i=45, 46, 58 : lmt_registerglyph [ category = "segments", private = "segment other " & utfchr(i), tounicode = i, code = "Segment(" & (decimal i) & ")", ] ; endfor ; lmt_registerglyph [ category = "segments", private = "segment elements", code = "Segment(100)" ] ; lmt_registerglyph [ category = "segments", private = "segment diagonals", code = "Segment(101)" ] ; for i=67, 69, 78, 79, 84, 88 : lmt_registerglyph [ category = "segments", private = "segment letter " & utfchr(i), tounicode = i, code = "Segment(" & (decimal i) & ")", ] ; endfor ; \stopMPcalculation \startluacode fonts.handlers.otf.addfeature { name = "segmentdigits", type = "substitution", nocheck = true, data = { [0x30] = 0x1FBF0, [0x31] = 0x1FBF1, [0x32] = 0x1FBF2, [0x33] = 0x1FBF3, [0x34] = 0x1FBF4, [0x35] = 0x1FBF5, [0x36] = 0x1FBF6, [0x37] = 0x1FBF7, [0x38] = 0x1FBF8, [0x39] = 0x1FBF9, [0x41] = "segment digit A", [0x42] = "segment digit B", [0x43] = "segment digit C", [0x44] = "segment digit D", [0x45] = "segment digit E", [0x46] = "segment digit F", -- [0x2E] = "segment period", [0x2D] = "segment other -", [0x2E] = "segment other .", [0x3A] = "segment other :", } } -- todo: support a mix of gpos and gsub -- local kern = { [fonts.helpers.privateslot("segment period")] = -1230 } -- well ... -- local kern = { ["segment period"] = -1230 } -- well ... local kern = { ["segment other ."] = -1230 } -- well ... fonts.handlers.otf.addfeature { name = "segmentperiod", type = "kern", nocheck = true, data = { [0x1FBF0] = kern, [0x1FBF1] = kern, [0x1FBF2] = kern, [0x1FBF3] = kern, [0x1FBF4] = kern, [0x1FBF5] = kern, [0x1FBF6] = kern, [0x1FBF7] = kern, [0x1FBF8] = kern, [0x1FBF9] = kern, ["segment digit A"] = kern, ["segment digit B"] = kern, ["segment digit C"] = kern, ["segment digit D"] = kern, ["segment digit E"] = kern, ["segment digit F"] = kern, }, } fonts.handlers.otf.addfeature { name = "segmentextras", type = "chainsubstitution", prepend = 1, nocheck = true, lookups = { { type = "substitution", data = { ["C"] = "segment letter C", ["O"] = "segment letter O", ["N"] = "segment letter N", ["T"] = "segment letter T", ["E"] = "segment letter E", ["X"] = "segment letter X", }, }, }, data = { rules = { { current = { { "C" }, { "O" }, { "N" }, { "T" }, { "E" }, { "X" }, { "T" } }, lookups = { 1, 1, 1, 1, 1, 1, 1 }, }, }, } } \stopluacode \definefontfeature [segments] [metapost=segments] \definefontfeature [boldsegments] [metapost={category=segments,weight=2.0,offset=.2}] \definefontfeature [segmentdigits] [segmentdigits=yes, segmentextras=yes, segmentperiod=yes] \definefontfeature [default] [default] [metapost={category=segments,weight=1.2}] % [metapost=segments] \definehighlight [Digits] [style=\addfeature{segmentdigits}] \continueifinputfile{meta-imp-segments.mkxl} \setupbodyfont[dejavu] \showglyphs \startTEXpage[offset=1ts] These old texies grew up with these segmented characters with funny descenders on top of the baseline, but digits are fine: \Digits{{\middlered-12345}{\middleblue.}{\middlegreen67890}} also in \Digits{12:34}. We also provide some hexadecimal symbols but these are not in unicode: \Digits{ABCDEF}. And we have a bonus: \Digits{like this CONTEXT here}. \stopTEXpage \stoptext