6

I have seen a post (Editing theorem environments) explaining how to customize the theorem environment in LaTeX, using the thmbox package.

original

I would like the same output for my document but I only use ConTeXt and I am not an expert on TeX. Can someone tell me how to achieve this from scratch or using the ConTeXt mechanisms? Also, I would prefer if:

  • the rule were thicker
  • the corner were rounded
  • the bottom rule spanned the whole page
  • the environnement could split across pages

Like this :

modified

Thanks in advance!

3 Answers3

8

Here is an alternative solution. Let's start with a version that doesn't break across pages. We'll fix that later.

First, let's try to get the basic layout without the frames. Unlike the other solutions, I don't move the theorem head to the right, rather I move the theorem body to the left.

\defineenumeration[THEOREMenumeration]
                  [
                    text=Theorem ,%Space after Theorem is delibrate
                    title=yes,
                    alternative=hanging, 
                    titlestyle=boldslanted, % or bolditalic
                    style=slanted, % or italic
                    width=fit,
                 ]


\define\starttheorem
  {\dosingleargument\dostarttheorem}

\def\dostarttheorem[#1]%
    {\startTHEOREMenumeration[#1]%
     \crlf
     }

\define\stoptheorem
    {\stopTHEOREMenumeration
    }


\starttext
\input ward
\starttheorem[title={Riemann-Lebesgue}]
  \input ward
  Pour tout $f \in L^1({\Bbb T})$, on a
  \startformula
    \lim_{|n| \to ∞} c_n(f) = 0
  \stopformula
\stoptheorem

\input knuth
\stoptext

which gives:

enter image description here

Now all we need is the frame. To get the bottom rule around the theorem head, you can use:

\defineenumeration[THEOREMenumeration]
                  [
                    ....
                    headcommand=\THEOREMframed,
                 ]

where \THEOREMframed is defined as:

  \defineframed     [THEOREMframed]
                    [
                      frame=off,
                      bottomframe=on,
                      location=low,
                      rulethickness=2bp,
                    ]

which gives:

enter image description here

The rule overlaps with the next line, but we'll fix this later.

Now, to get the frame around the theorem body, change the definitions of \starttheorem and \stoptheorem to:

\def\dostarttheorem[#1]%
    {\startTHEOREMenumeration[#1]%
     \startTHEOREMframedtext
     }

\define\stoptheorem
    {\stopTHEOREMframedtext
     \stopTHEOREMenumeration
    }

where THEOREMframedtext is defined as:

\defineframedtext [THEOREMframedtext]
                  [
                    offset=0pt,
                    loffset=1em,
                    boffset=1em,
                    corner=15,
                    width=broad,
                    rulethickness=2bp,
                    before=,
                    after=,
                    strut=no,
                  ]

which gives:

enter image description here

Note that the theorem is now too broad. We can fix that by using:

\defineframedtext [THEOREMframedtext]
                  [ 
                  ....
                    width=\dimexpr(\hsize-\framedparameter{loffset} -\framedparameter{rulethickness})\relax,
                  ....
                  ]

Here is the complete code:

\defineenumeration[THEOREMenumeration]
                  [
                    text=Theorem ,%Space after Theorem is delibrate
                    title=yes,
                    alternative=hanging, 
                    titlestyle=boldslanted, % or bolditalic
                    style=slanted, % or italic
                    width=fit,
                    headcommand=\THEOREMframed,
                 ]

  \defineframed     [THEOREMframed]
                    [
                      frame=off,
                      bottomframe=on,
                      location=low,
                      rulethickness=2bp,
                    ]

\defineframedtext [THEOREMframedtext]
                  [
                    offset=0pt,
                    loffset=1em,
                    boffset=1em,
                    corner=15,
                    width=\dimexpr(\hsize-\framedparameter{loffset} -\framedparameter{rulethickness})\relax,
                    rulethickness=2bp,
                    before=,
                    after=,
                    strut=no,
                  ]



\define\starttheorem
  {\dosingleargument\dostarttheorem}

\def\dostarttheorem[#1]%
    {\startTHEOREMenumeration[#1]%
     \startTHEOREMframedtext
     }

\define\stoptheorem
    {\stopTHEOREMframedtext
     \stopTHEOREMenumeration
    }


\starttext
\input ward
\starttheorem[title={Riemann-Lebesgue}]
  \input ward
  Pour tout $f \in L^1({\Bbb T})$, on a
  \startformula
    \lim_{|n| \to ∞} c_n(f) = 0
  \stopformula
\stoptheorem

\input knuth
\stoptext

Now, to make sure that the body can split across the page, we need to change the framedtext with a textbackground. The keys of textbackgroud are different from that of framedtext. We start with:

\definetextbackground [THEOREMframedtext]
                  [
                    mp=ellframe,
                    location=paragraph,
                    leftoffset=1em,
                    topoffset=1.5ex,
                    bottomoffset=1em,
                    rightoffset=0pt,
                    rulethickness=2bp,
                    framecolor=black,
                    before=,
                    after=,
                    strut=no,
                  ]

enter image description here

Now all we need to do is define the metapost graphic ellframe that draws the L-shaped frame. Before we do that, we need to decide what happens when the theorem overflows a page: should we draw L-shaped frames on both pages, or should we draw a straight line on the first page and an L-shaped frame on the second? What happens in the unlikely scenario that the theorem spans three pages? ConTeXt makes it easy to write code specialized to each scenario.

\startuseMPgraphic{ellframe}
  begingroup;
    interim linecap := butt ;
    for i=1 upto nofmultipars :
      if multikind[i] = "single" :
          draw ( ulcorner multipars[i] -- 
               ( llcorner multipars[i] + (0, boxlineradius )){down} ..
               {right}(llcorner multipars[i] + (boxlineradius, 0) ) --
                 lrcorner multipars[i] )
      elseif multikind[i] = "first" :
          draw leftboundary   multipars[i] 
      elseif multikind[i]= "middle" :
          draw leftboundary  multipars[i] 
      elseif multikind[i]= "last" :
          draw ( ulcorner multipars[i] -- 
               ( llcorner multipars[i] + (0, boxlineradius )){down} ..
               {right}(llcorner multipars[i] + (boxlineradius, 0) ) --
                 lrcorner multipars[i] )
      fi 
      boxlineoptions withpen pencircle scaled boxlinewidth ;
    endfor ;
  endgroup;
\stopuseMPgraphic

This is the output when there is no page break:

enter image description here

And this is the output when the theorem breaks across pages:

enter image description here

Here is the final complete code:

\defineenumeration[THEOREMenumeration]
                  [
                    text=Theorem ,%Space after Theorem is delibrate
                    title=yes,
                    alternative=hanging, 
                    titlestyle=boldslanted, % or bolditalic
                    style=slanted, % or italic
                    width=fit,
                    headcommand=\THEOREMframed,
                 ]

\defineframed     [THEOREMframed]
                  [
                    frame=off,
                    bottomframe=on,
                    location=low,
                    rulethickness=2bp,
                  ]

\definetextbackground [THEOREMframedtext]
                  [
                    mp=ellframe,
                    location=paragraph,
                    leftoffset=1em,
                    topoffset=1.5ex,
                    bottomoffset=1em,
                    rightoffset=0pt,
                    rulethickness=2bp,
                    framecolor=black,
                    before=,
                    after=,
                    strut=no,
                  ]

\startuseMPgraphic{ellframe}
  begingroup;
    interim linecap := butt ;
    for i=1 upto nofmultipars :
      if multikind[i] = "single" :
          draw ( ulcorner multipars[i] -- 
               ( llcorner multipars[i] + (0, boxlineradius )){down} ..
               {right}(llcorner multipars[i] + (boxlineradius, 0) ) --
                 lrcorner multipars[i] )
      elseif multikind[i] = "first" :
          draw leftboundary   multipars[i] 
      elseif multikind[i]= "middle" :
          draw leftboundary  multipars[i] 
      elseif multikind[i]= "last" :
          draw ( ulcorner multipars[i] -- 
               ( llcorner multipars[i] + (0, boxlineradius )){down} ..
               {right}(llcorner multipars[i] + (boxlineradius, 0) ) --
                 lrcorner multipars[i] )
      fi 
      boxlineoptions withpen pencircle scaled boxlinewidth ;
    endfor ;
  endgroup;
\stopuseMPgraphic

\define\starttheorem
  {\dosingleargument\dostarttheorem}

\def\dostarttheorem[#1]%
    {\startTHEOREMenumeration[#1]%
     \page[no]
     \startTHEOREMframedtext
     }

\define\stoptheorem
    {\stopTHEOREMframedtext
     \stopTHEOREMenumeration
    }
Aditya
  • 62,301
4

Inspired by the Metafun manual (search it for FunnyFrame) and this thread on the ConTeXt list. It satisfies some of your queries, but it does not split over pages. I don't know how to do that. Also, it is rather manual. There might be better ways of doing this kind of thing, so see it as a start.

\definenumber[ThmNumber][way=bychapter, prefix=no]
\setnumber[ThmNumber][1]


\startuseMPgraphic{FunnyFrame}
picture p ; numeric w, h, o ; path f;
p := textext.rt(\MPstring{ThmTitle}) ;
w := OverlayWidth ; h := OverlayHeight ; o := BodyFontSize ;
p := p shifted (-o,h) ; draw p ;
drawoptions (withpen pencircle scaled 1pt) ;


pair pf;
pf := lrcorner p;
draw lrcorner p -- llcorner p ;
f := (0,ypart pf) -- (0,1mm){down}..{right}(1mm,0)--(w-o,0);
draw f;
setbounds currentpicture to unitsquare xyscaled(w,h) ;
\stopuseMPgraphic


\defineoverlay[FunnyFrame][\useMPgraphic{FunnyFrame}]


\defineframedtext[Thm]
[frame=off,
style=\it,
background=FunnyFrame,
offset=\bodyfontsize,
width=\dimexpr(\textwidth+\bodyfontsize),
before={\blank[line]},
after={\incrementnumber[ThmNumber]\blank}]

\define[2]\FrameTitle%
{\setMPtext{ThmTitle}{\hbox{\hss\strut\bf #1 \namedheadnumber{chapter}.\getnumber[ThmNumber] {\em #2}\hss}}}

\starttext

\chapter{Test chapter}
\setnumber[ThmNumber][1]

\FrameTitle{Theorem}{(Pythagoras)}
\startThm
It holds that
\startformula
a^2+b^2=c^2.
\stopformula
\stopThm
\input Zapf
\FrameTitle{Lemma}{}
\startThm
If $a>b$ and $c>0$ then $ac>bc$. \input tufte\par
\stopThm

enter image description here

mickep
  • 8,685
4

Here is a simple solution but only similar to the question. I use description and frames.

    \defineframedtext[styletheoreme]
                     [frame=on,%
                      rulethickness=1mm,%
                      strut=no,%
                      width=0.6\paperwidth,%
                      location=middle,%
                      corner=15,% 
                      toffset=-8mm,% 
                     ]
    \defineframed[titretheoreme]
                     [frame=off,%
                      bottomframe=on,
                      rulethickness=1mm,%
                      width=fit,%
                      location=top,%
                      toffset=-5mm,%
                     ]
    \definedescription[theoreme][width=fit,%
                                 alternative=top,%
                                 headcommand={\hskip -10mm \titretheoreme},%     
                                 before={\startstyletheoreme},%
                                 after={\stopstyletheoreme}%                    
                                  ]


    \starttext
    \starttheoreme{Un théorème}

    Blabla
    \startformula
    \sum_{k=1}^n k = \frac{n(n+1)}2
    \stopformula
    \stoptheoreme
\stoptext

corner=15 is documented in http://wiki.contextgarden.net/Framed#Rounded_Corners toffset=-8mm allow to lower the frame

You'll have to adjust the dimensions.

It doesn't split over pages.

enter image description here

ericD13
  • 91