上下文:列表 -> 表格

上下文:列表 -> 表格

我有一个列表(不是表格),我想将其排版为用于归档标签的网格。该列表采用类似 CSV 的格式,并带有注释,其中相似的条目被分组到一行中。

\startseparatedlist[NaturalTable]
One,One.Two,One.Three
Two
Three
#Four
Five
\stopseparatedlist

标签尺寸固定:2 英寸 x 0.5 英寸:

\startsetups labels
    \setupTABLE[row][each,width=2in,height=0.5in,align={middle,lohi}]
\stopsetups

排版要求:

  1. 每行的表格单元格基于\makeupwidth / labelwidth而不是 CSV 列。使用该database模块需要一些状态来跟踪何时添加\eTR/\bTR命令。
  2. 标签应可折叠,并带有虚线。我的想法是每个标签两行。顶行的底部框架是虚线(如何:MetaPost?)并且单元格是空的。底行包含实际内容。
  3. 按行主序排列。

这是一个最小的非工作示例:

从...来:

% Width should control the cells per row.
\setuplayout
    [ backspace=0.75in
    , width=7in
    ]

\definemagiccommand[NaturalTable]
    [ width=2
    , height=1
    , ...=..., === % Maybe inherit from or wrap \defineseparatedlist?
    ]

\magiccommand[NaturalTable]
    One,One.Two,One.Three
    Two
    Three
    #Four
    Five
    Six
\stopmagiccommand

到:

示例标签结果图像

请注意,最终结果中的所有线条都是相同的粗细。我通过手动删除 MetaFun 中的重叠线条来实现这一点,这并不好玩(而且仍然不完美,请参见右下角)。


这是我目前所拥有的。问题非常明显,我为每个问题创建了一个 MWE。

\startuseMPgraphic{dottedBottom}
    draw bottomboundary OverlayBox withpen pencircle scaled \frameddimension{rulethickness} dashed withdots;
    setbounds currentpicture to boundingbox OverlayBox;
\stopuseMPgraphic

\defineoverlay[dottedBottom][\useMPgraphic{dottedBottom}]

\startsetups label
    \setupTABLE[frame=off,width=2in,height=0.5in]
    \setupTABLE[row][each][align={middle,lohi}]
    \setupTABLE[row][first][background={dottedBottom}]
\stopsetups

\define[1]\framedlabel{%
    \framed[strut=no,offset=0pt]{%
        \bTABLE[setups=label,split=yes]%
            \bTR \bTD \eTD \eTR%
            \bTR \bTD #1 \eTD \eTR%
        \eTABLE%
    }\hskip 0pt }


\vbox{
    \rightskip 0pt plus 1fil
    \setupinterlinespace[off]
    \leavevmode
    \framedlabel{One}
    \framedlabel{Two}
    \framedlabel{Three}
    \framedlabel{Four}
    \framedlabel{Five}
    \framedlabel{Six}
}


\usemodule[database]

\define\framedlabelfor{
    %TODO
}

\defineseparatedlist[LabelsCSV][separator=comma,command=\framedlabelfor]

\definestartstop[Labels]
    [ before={\vbox\bgroup\rightskip 0pt plus 1fil\setupinterlinespace[off]\leavevmode\startLabelsCSV}
    , after={\stopLabelsCSV\egroup}
    ]

如何避免出现重复线:

\setuplayout
    [ backspace=0.75in
    , width=7in
    ]

\vbox{
    \rightskip 0pt plus 1fil
    \setupinterlinespace[off]
    \leavevmode
    \framed[height=1in,width=2in]{001}\hskip0pt
    \framed[height=1in,width=2in]{002}\hskip0pt
    \framed[height=1in,width=2in]{003}\hskip0pt
    \framed[height=1in,width=2in]{004}\hskip0pt
    \framed[height=1in,width=2in]{005}\hskip0pt
    \framed[height=1in,width=2in]{006}\hskip0pt
    \framed[height=1in,width=2in]{007}\hskip0pt
}

编辑\frameoffset:我通过将设置为的一半解决了双线问题\rulethickness。不幸的是,现在有明显的故障,2 线和 3 线交叉点中无对立线略微延伸到交叉点之外。请参阅附图。这些是舍入误差吗 - 它们只发生在小于的偏移处1pt?我该如何摆脱它们?

\vbox{
    \rightskip 0pt plus 1fil
    \setupinterlinespace[off]
    \leavevmode
    \framed[height=1in,width=2in,rulethickness=1pt,frameoffset=0.5pt]{001}\hskip0pt
    \framed[height=1in,width=2in,rulethickness=1pt,frameoffset=0.5pt]{002}\hskip0pt
    \framed[height=1in,width=2in,rulethickness=1pt,frameoffset=0.5pt]{003}\hskip0pt
    \framed[height=1in,width=2in,rulethickness=1pt,frameoffset=0.5pt]{004}\hskip0pt
    \framed[height=1in,width=2in,rulethickness=1pt,frameoffset=0.5pt]{005}\hskip0pt
    \framed[height=1in,width=2in,rulethickness=1pt,frameoffset=0.5pt]{006}\hskip0pt
    \framed[height=1in,width=2in,rulethickness=1pt,frameoffset=0.5pt]{007}\hskip0pt
}

故障:直角线超出交叉点

以及如何创建 varargs 命令:

\define\foreach{
    % TODO
}

\foreach{001}
\foreach{001}{002}

答案1

commanddatabase模块示例抛出 Lua 错误,所以我放弃了 varargs 宏问题,自己用 Lua 处理缓冲区。中途我意识到我更喜欢 Lua 表语法而不是 CSV 语法,所以提供了两种方法。第一种方法是混合使用 Lua/ConTeXt 来处理 CSV。另一种是 Lua-only,适用于将数据存储在 Lua 中的情况。

这些字段是单独处理的,这使得它不适合表格数据,不像database在记录级别工作的模块。支持嵌套数据就像修改函数一样简单csvforeach,例如,如果我想添加仅在索引中可见的描述字段。使用 Lua 表的主要优势是将格式与结构分离。

\setuppapersize[letter]

% text heigh/width: 9in/7in
\setuplayout
    [ topspace=0.5in
    , height=10in
    , header=0.5in
    , footer=0.5in
    , backspace=0.75in
    , width=7in
    , leftmargindistance=0.15in
    , leftmargin=0.6in
    , rightmargindistance=0.15in
    , rightmargin=0.6in
    ]

\setupcolors[state=start]

\startluacode
    userdata = userdata or {}

    function userdata.parsecsv(s)
        local field = '"' * lpeg.Cs(((1 - lpeg.P'"') + lpeg.P'""'/'"')^0) * '"'
                          + lpeg.C((1 - lpeg.S'",\r\n')^0)
        local record = lpeg.Ct(field * ("," * field)^0)
        local file = lpeg.Ct(record * (lpeg.S"\r\n" * record)^0 * (lpeg.P"\r\n" + -1))
        return lpeg.match(file,s)
    end

    function userdata.csvforeach(t,c)
        local i = 0
        for r,v in ipairs(t) do
            for f,v in ipairs(v) do
                i = i + 1
                if type(c) == "function" then
                    c(i,v)
                else
                    context("%s{%s}{%s}",c,i,v)
                end
            end
        end
    end
\stopluacode

\define[2]\csvforeach{%
    \ctxlua{%
        userdata.csvforeach(userdata.#1,"\luaescapestring{\normalunexpanded{#2}}")}}

\def\startcsv{\dosingleempty\dostartcsv}

\def\dostartcsv[#1]%
    {\iffirstargument
        \def\csvName{#1}
     \else
        \def\csvName{csv}
     \fi
     \dostartbuffer
        [\csvName]
        [startcsv]
        [stopcsv]}

\def\stopcsv%
    {\ctxlua
        {userdata.\csvName = userdata.parsecsv(buffers.getcontent("\csvName"))}}

\startuseMPgraphic{dottedBottom}
    draw bottomboundary OverlayBox withpen pencircle scaled \frameddimension{rulethickness} dashed withdots;
    setbounds currentpicture to boundingbox OverlayBox;
\stopuseMPgraphic

\defineoverlay[dottedBottom][\useMPgraphic{dottedBottom}]

\startsetups label
    \setupTABLE[frame=off,width=2in,height=0.5in]
    \setupTABLE[row][each][align={middle,lohi}]
    \setupTABLE[row][first][background={dottedBottom}]
\stopsetups

\startsetups labelframe
    \setupframed[strut=no,offset=0pt,rulethickness=1pt,frameoffset=0.5pt]
\stopsetups

\setuphead[title][
    align=middle,
    after={\hairline\blank[4*big]}
]

\setupcolumns[n=3,separator=rule,balance=yes,distance=0.5in]

\define[2]\framedlabel{%
    \setup{labelframe}%
    \framed{%
        \bTABLE[setups=label,split=no]%
            \bTR \bTD \eTD \eTR%
            \bTR \bTD \startitemize \sym{#1.} #2 \stopitemize \eTD \eTR%
        \eTABLE%
    }\hskip 0pt }

\define[2]\labelitem{\sym{#1.} #2}

\startcsv
Of,course
    ,it is!
\stopcsv

\starttext

\vbox{
    \rightskip 0pt plus 1fil
    \setupinterlinespace[off]
    \leavevmode
    \csvforeach{csv}{\framedlabel}
}

\title{Index}

\resetcounter[userpage]

\startcolumns
\startitemize
\csvforeach{csv}{\labelitem}
\stopitemize
\stopcolumns

\page[yes]

% If you prefer Lua, might as well stay in Lua.

\startluacode
    local sp = 65536
    context.vbox(function()
        tex.setglue("rightskip", 0, sp, 0, 2, 0)
        context.setupinterlinespace({"off"})
        context.leavevmode()
        userdata.csvforeach(userdata.csv,context.framedlabel)
    end)

    context.title("Index")
    context.resetcounter({"userpage"})
    context.startcolumns()
    context.startitemize()
    userdata.csvforeach(userdata.csv,context.labelitem)
    context.stopitemize()
    context.stopcolumns()
    context.page({"yes"})
\stopluacode

% Now using Lua tables rather than CSV.


\define\eachtigpar{\EveryPar{%
    \clubpenalties  5 10000 10000 10000 100 0%
    \widowpenalties 5 10000 10000 10000 100 0%
}}

\defineitemgroup[tig]
    [inner=\eachtigpar]


\define[2]\labelitem{\sym{#1.} #2}
\define[1]\labeldescription{\blank[medium]\page[no]#1}

\startluacode
    local data =
        { "One", "Two"
        , "Three"
        , "Four"
        ,{"Five", [=[
                  This deserves an explanation. The explanation
                  is multiple lines long because of \ConTeXt.
                  \startitemize
                  \item Reason one.
                  \item Reason two.
                  \stopitemize
                  ]=]}
        , "six"
        , "seven"
        }

    local function dedent(s)
        local lx,fx = {},{}
        for l in s:gmatch("[^\n]*") do
            if l:match("^%s*$") then
                table.insert(lx,"")
            else
                table.insert(lx,l)
                table.insert(fx,l)
            end
        end
        if #fx ~= 0 then
            local i,s,c,n = 0,false
            while true do
                for _,v in pairs(fx) do
                    if #v - i == 0 then
                        s = true
                        break
                    end
                    n = string.sub(v,i+1,i+1)
                    if not n:match("^%s") then
                        s = true
                        break
                    end
                    if c == nil then
                        c = n
                    elseif c ~= n then
                        s = true
                        break
                    end
                end
                if s then
                    break
                end
                c = nil
                i = i + 1
            end
            for k,v in pairs(lx) do
                lx[k] = string.sub(v,i+1)
            end
        end
        return table.concat(lx,"\n")
    end

    local function trim(s)
        return s:match("^%s*(.-)%s*$")
    end

    local function tableforeach(t,c)
        local i = 0
        for _,v in ipairs(t) do
            local d
            i = i + 1
            if type(v) == "table" then
                v,d = unpack(v)
            end
            if d then
                d = trim(dedent(d))
            end
            c(i,v,d)
        end
    end

    local function tablelabel(i,v,d)
        context.framedlabel(i,v)
    end

    local function tableindex(i,v,d)
        context.labelitem(i,v)
        if not d then
            return
        end
        context.labeldescription(d)
    end

    local sp = 65536
    context.vbox(function()
        tex.setglue("rightskip", 0, sp, 0, 2, 0)
        context.setupinterlinespace({"off"})
        context.leavevmode()
        tableforeach(data,tablelabel)
    end)

    context.title("Index")
    context.resetcounter({"userpage"})
    context.startcolumns()
    context.starttig()
    tableforeach(data,tableindex)
    context.stoptig()
    context.stopcolumns()
    context.page({"yes"})
\stopluacode

\stoptext

它主要通过列和项组格式化来完成仍需要一些工作

相关内容