1

I am (ab)using a framed listings environment include an enumeration environment (by escaping to latex). This compiles fine but in the resulting pdf the frame around the listing is interrupted.

Minimal working example:

\documentclass{report}

\usepackage[english]{babel}
\usepackage{float}
\usepackage[margin=10pt,font=small,labelfont=bf,justification=centering]{caption}

\usepackage{listings}
\renewcommand{\lstlistingname}{Box}
% Setup for listings:
\lstset{extendedchars=true,
    tabsize=3,
    frame=single,
    frameround=tttt,
    showspaces=false,
    framesep=10pt,
    boxpos=c,
    float=h,
    captionpos=b,
    escapechar=\%
}
\lstdefinestyle{Normaltext}{language=,numbers=none,basicstyle=\normalfont}

\lstnewenvironment{textbox}[2]
{%
\centering
\minipage{0.9\textwidth}
\lstset{style=Normaltext,label=#1,caption=#2}
}
{%
\endminipage
\endcenter
}

\begin{document}

\begin{textbox}{box:somelabel}{some caption}
%{Test 1 2 3, here comes the enumeration:
\begin{itemize}
\item item 1
\item item 2
\item item 3
\item item 4
\end{itemize}
}%
\end{textbox}

\end{document}

This produces something like this: Interrupted listing frame

Any ideas how I can avoid that the frame is interrupted?

Or maybe somebody can suggest a better alternative to abusing listings for putting plain latex text in a frame box, because that's all I really wanted. Basically what I want to achieve is this:

  • I want 3 types of "objects" in my document: figures, tables and boxes.
  • Figures have the "Figure" label and are listed in the listoffigures.
  • Tables have the "Table" label and are listed in the listoftables.
  • Similarly I want boxes to have the "Box" label and be listed in a listofboxes (I was planning to use listoflistings for this).
  • Boxes can either contain source code (using listings package) or plain latex text, but either way they should have the same rounded frame around them and be centered on the page and cover 90% of textwidth (I was using minipage for this, as you can see in my code).
Matthias
  • 4,051

2 Answers2

2

The framed or mdframed packages allow you to put text in frames. Here's a way to do what you want with mdframed.

\documentclass{article}
\usepackage{caption}
\usepackage{listings}
\lstset{extendedchars=true,
    tabsize=3,
    frame=none,
    showspaces=false,
    boxpos=c,
    float=h,
    escapechar=\%
}
\usepackage[style=1]{mdframed}
\newcounter{boxctr}
\DeclareCaptionType{boxx}
\usepackage{needspace}
\newenvironment{Boxx}[2]{%
  \captionsetup{type=boxx}
  \begin{mdframed}[%
    linewidth=1pt,
    roundcorner=10pt,%
    leftmargin=.05\textwidth,
    rightmargin=.05\textwidth,
    skipabove=.7\baselineskip]%
    \refstepcounter{boxctr}%
    \label{#1}%
    \gdef\boxxcaption{\caption{#2}}
    \needspace{2\baselineskip}
  }{%
  \end{mdframed}%
  \boxxcaption%
}
\usepackage{lipsum}
\begin{document}
This is a reference to Box~\ref{box:one}!
\vspace{1.5cm}
\lipsum[1-4]
\begin{Boxx}{box:one}{This is a caption}
  \begin{enumerate}
  \item One
  \item Two
  \item Three
  \end{enumerate}
\end{Boxx}
\lipsum[1]
\begin{Boxx}{box:two}{This is also a caption}
  \begin{lstlisting}
    Also works with listings

    \foo is escaped!
  \end{lstlisting}
\end{Boxx}
\lipsum[2]
\end{document}

Boxes take two extra arguments: a label and a caption, just like the environment defined in the question. They use the caption package's captioning magic. So this should make doing lists of boxes easier. The label should stick with the bottom of the box now. This might lead to some ugly whitespace, but other than making the boxes float, this is probably as good as it gets.

Seamus
  • 73,242
  • Seamus: most importantly I want them to look the same as source code listings (rounded frame, centered, 90% width minipage, same caption label) I edited the original question to explain what I want. – Matthias Aug 17 '11 at 13:12
  • OK. Everything apart from the "list of boxes" is easy (and should work in the above code). A list of boxes from scratch is trickier. Maybe there is a better way to escape from listings to allow you to use \listoflistings... – Seamus Aug 17 '11 at 13:31
  • Thanks Seamus. However, I don't see the frame using your example. Also, I think I will need proper captions and labels to refer to the boxes and have them in a "list of boxes" at the end. – Matthias Aug 17 '11 at 13:31
  • Otherwise, it's a matter of making a new auxiliary file and writing each box to it... – Seamus Aug 17 '11 at 13:31
  • Somehow the frames are invisible in the result. Any idea why? – Matthias Aug 17 '11 at 13:36
  • How are you compiling it? There should be a frame... – Seamus Aug 17 '11 at 13:36
  • I'm using pdflatex (MikTex on Windows7) – Matthias Aug 17 '11 at 13:39
  • Try changing style=1 to style=3, that might work to have the lines show up. I've updated the example to include captions and a reference mechanism built into the environments, as per your original example. – Seamus Aug 17 '11 at 13:44
  • Thanks again, it's getting better and better. style=3 gives me an error about requiring pstricks. style=0 does work but the frames are not rounded. – Matthias Aug 17 '11 at 14:11
  • OK stick with style=1 but Try adding linewidth=1pt to the list of options: maybe it's your pdf viewer failing to resolve the thin default line... Or try a different PDF viewer or try zooming in... – Seamus Aug 17 '11 at 14:16
  • 1
    Regarding the list: Since the caption package is loaded anyway one can use \DeclareCaptionType{boxx} and (re)define the boxx environment afterwards. Simply place \captionsetup{type=boxx} at first line of environment code (this will place the hyperref anchor, if necessary, and will initialize the use of \caption) and do the captions with \caption. –  Aug 17 '11 at 14:26
  • @Axel: Thanks. Will this also allow me to generate the list of boxes? – Matthias Aug 17 '11 at 14:39
  • @Seamus: linewidth=1pt still doesn't make it visuable, nor does 5pt. I am using Acrobat Pro, as well as the built-in pdf viewer of TexMaker. Neither shows the frame. No matter how far I zoom in. Maybe the frame has a white color or something? – Matthias Aug 17 '11 at 14:40
  • @Matthias I think you should ask another question about mdframed lines not showing up. It might have something to do with not having the right version of tikz. In any case, it doesn't really relate to the subject of this current question. – Seamus Aug 17 '11 at 14:46
  • @Axel: I figured out how to use declarecaption and I got the "list of boxxs" working. Thanks! – Matthias Aug 17 '11 at 15:02
  • @Seamus: Guess you are right. I'll open another question for that issue. Thanks for all your help! – Matthias Aug 17 '11 at 15:02
  • @Seamus: one other problem remains: the box and it's caption are not kept on the same page. Is there any way to force them to stay together? – Matthias Aug 17 '11 at 15:25
  • @Seamus: I fixed the frame not showning problem. It was drawing the line in white I think. However, linecolor=black was not enough to make it show up. But this was: linecolor=black, innerlinecolor=black, middlelinecolor=black, outerlinecolor=black, – Matthias Aug 17 '11 at 15:43
  • Ok, I managed to fix the pagebreak between the frame and the caption by using \nopagebreak. Now only one problem remains: if a "boxx" appears at the top of a page that hyperref anchor is put at the bottom of the previous page. So in fact \captionsetup{...} and the actual frame are separated by pagebreak. Any idea how to fix this? Axel maybe you know? – Matthias Aug 17 '11 at 16:26
  • @Matthias that is strange about mdframed. It's clearly not working as expected. Try looking with another pdf reader in case it's a "problem" with acrobat pro. See the updated solution with needspace to keep the caption with the box. – Seamus Aug 17 '11 at 16:32
  • @Matthias maybe put the captionsetup inside the mdframed? – Seamus Aug 17 '11 at 16:32
  • @Seamus: Why do you use an own counter called boxctr? IMHO there is no need for it, placing the \label after the caption should be sufficient: \gdef\boxxcaption{\caption{#2}\label{#1}}. –  Aug 17 '11 at 16:44
  • @Seamus, Matthias: If you move the \captionsetup inside mdframed, the caption will not work since it will be typeset outside the mdframed environment. Maybe a \nopagebreak will help instead? Unfortunately I do not have much time now, will play around with it tomorrow... –  Aug 17 '11 at 16:49
  • @Seamus: placing captionsetup inside mdframed gives an error. @Axel: \newenvironment{Boxx}[2]{% \gdef\boxxcaplab{\caption{#2}\label{#1}} \captionsetup{type=boxx} \begin{mdframed}[% linewidth=1pt, linecolor=black, innerlinecolor=black, middlelinecolor=black, outerlinecolor=black, roundcorner=10pt, leftmargin=.05\textwidth, rightmargin=.05\textwidth, skipabove=.7\baselineskip, skipbelow=.7\baselineskip] \nopagebreak }{ \end{mdframed} \boxxcaplab } But this still puts the hyperref anchor on the previous page in case of pagebreak. – Matthias Aug 17 '11 at 16:50
  • ...or simply put the whole stuff inside a minipage. This will definitely suppress page breaks. –  Aug 17 '11 at 16:53
  • @Matthias: The \nopagebreak should be placed right before \begin{mdframed}. –  Aug 17 '11 at 16:54
  • @Axel: putting \nopagebreak before \begin{mdframed} does not fix the anchor problem. I tried a minipage but that causes the margins to shift because apparently I cannot make the minipage as wide as \textwidth EDIT: i said putting \nopagezbreak before \begin{mdframed} caused an error but that was a mistake – Matthias Aug 17 '11 at 17:19
  • Ok, I think I fixed it: \newenvironment{framed}[2]{% \gdef\caplab{\caption{#2}\label{#1}} \pagebreak[2] \captionsetup{type=framedbox} \nopagebreak \begin{mdframed}...

    The \pagebreak[2]suggests a pagebreak to happen before \captionsetup. This fixes the problem of the hyper anchor remaining on the previous page, and as far as my example goes it does not cause unwanted "mid-page" pagebreaks. Do you guys think this is a proper solution?

    – Matthias Aug 17 '11 at 17:41
  • 1
    Looks ok to me. I just have modified Seamus example code so a minipage is used. Furthermore I removed the own counter, and use \caption@freeze and \caption@defrost instead of \boxxcaption so ordinary \caption can be used (with optional argument), and \ContinuedFloat and \captionsetup will work inside boxx, too. I uploaded it to http://latex.sommerfeldt.f-m.fm/test.tex Maybe some of the stuff used there is of any use for you? –  Aug 17 '11 at 18:38
  • @Axel: thanks a lot! I started using the freeze/defrost because it is indeed practical to be able to use \caption with optional argument. However, the downside seems to be that when using freeze/defrost I can no longer define labels in the boxx. I wanted to do this to refer to enumberation items. I already tried to pass the label as an argument to boxx again (and set it with \label inside the env definition, like seamus did before), but that doesn't fix it. I can only define labels in th boxx when I don't use freeze/defrost. Any idea on how to have both "in-boxx" labels and \caption? – Matthias Aug 17 '11 at 22:19
  • I have a quasi solution: \begin{boxx}{\caption[short]{long}\label{box:example}} ... \end{boxx}. In the renewnvironment I store #1 as \boxxcaplab with gdef and call it in the end part. This allows me to use \caption with optional arg, while still having labels in the boxx. Example: http://brussense.be/temp/Boxx.tex PDF: http://brussense.be/temp/Boxx.pdf – Matthias Aug 17 '11 at 23:14
  • 1
    @Matthias: Oh yes, you are right. \caption@freeze needs to redefine \label so it can utilize \caption and \label on \caption@defrost. You could include \let\Label\label just before \caption@freeze and use \Label for labeling your equations. (Of course this is only a workaround, will try to fix that for the caption package v3.2b right now...) –  Aug 18 '11 at 05:44
  • @Axel: great, i'll use \let\Label\label for now. Good luck fixing it in the package. Will you let us know on this page when it is done? – Matthias Aug 18 '11 at 07:44
  • @Matthias: Yes, of course. I'm just about fixing this and will put it to CTAN today. Will write a short comment if it is avail there. –  Aug 18 '11 at 09:03
  • Version 3.2b of the caption package is available now at ftp://dante.ctan.org/tex-archive/macros/latex/contrib/caption/ (It should be on the CTAN mirrors tomorrow.) –  Aug 18 '11 at 13:02
  • @Axel: I found a related problem when the caption package is used in combinaton with the cleveref package. Cleveref changes \label so it takes an optional type argument (this is a way to customize reference labels, see section 8 of the cleveref documentation). But when I use such a \label[type]{...} inside one of my boxxes this does not work. Even when not using freeze/defrost and \let\Label\label. – Matthias Aug 18 '11 at 13:06
  • @Matthias: Will check and fix that today evening or tomorrow morning. Will keep you informed. –  Aug 18 '11 at 13:16
  • @Axel: Great! Btw, I'm looking at v3.2b, but can you show me how this will allow me to do my in-boxx labels without \let\Label\label? – Matthias Aug 18 '11 at 13:26
  • With v3.2b the labels should simply work when using \caption@freeze and \caption@defrost (well, at least as long as they don't have an optional argument ;-)) If they don't, please drop me an e-mail with an example document showing the problem. (You'll find my e-mail address in the caption package documentation.) –  Aug 18 '11 at 16:34
  • Ok, I will test it. Just one question: how does it differentiate between the "in-boxx" labels and the boxx-label? Depending on whether they appear respectively before or after \caption? – Matthias Aug 18 '11 at 17:09
  • @Axel: v3.2b works fine! I e-mailed you about this. – Matthias Aug 18 '11 at 20:09
  • @Matthias: Every command which can be labelled (\caption, \section etc.) defines a "dog tag" (called \@currentlabel), and \label puts this tag into the aux file. So I simply set this tag to a special value when using \caption inside such environment. My version of \label checks if the tag is set to this special value or not. If not, the ordinary \label code will be used. –  Aug 19 '11 at 08:25
1

Because Seamus' answer was improved, thanks to additional input from Seamus and Axel Sommerfeldt (see discussion in comments), I think it is worthwhile to post a separate consolidated answer.

\documentclass{report}

\usepackage{color}
\usepackage{xcolor}

\usepackage[style=1]{mdframed}
\usepackage[font=small,labelfont=bf,justification=centering,belowskip=\baselineskip]{caption}
\usepackage[pdftex,bookmarks=true]{hyperref}%pagebackref=true
\usepackage{enumitem}
\usepackage{cleveref} %[nameinlink,noabbrev]

%%Paragraph indentation & spacing
\usepackage{parskip} %to disable paragraph indentation but still keep paragraphs separated (with \parskip)
\setlength{\parskip}{2.75ex plus 0.5ex minus 0.2ex}

\usepackage{listings}
\lstset{extendedchars=true,
    tabsize=3,
    frame=none,
    breaklines=true,
    breakautoindent=true,
    postbreak=\space,
    showspaces=false,
    keywordstyle=\color{blue},
    commentstyle=\color{red},
    stringstyle=\color{gray},
    identifierstyle=\color{black},
    framesep=0pt,
    boxpos=c,
    float=h,
    aboveskip=0pt,
    belowskip=0pt,
    escapechar=\%
}
\lstdefinestyle{Java}{language=Java, numbers=none, numberstyle=\tiny ,numbersep=5pt, basicstyle=\linespread{0.85}\scriptsize\ttfamily, showstringspaces=true}

\lstnewenvironment{java}{\lstset{style=Java}}{}

\usepackage{lipsum}
\usepackage{needspace} %\needspace{2\baselineskip}% %instead of \nopagebreak

\DeclareCaptionType[fileext=lob,placement=b,within=chapter]{boxx}[Box][List of Boxes]

\makeatletter
\caption@setbool{needfreeze}{true} %Tell the caption package that we would like to use \caption@freeze and \caption@defrost
\renewenvironment{boxx}
{%
  \pagebreak[2] %suggest pagebreak here
  \captionsetup{type=boxx,position=b} %skip BELOW the caption
  \nopagebreak
  \begin{mdframed}[%
    linewidth=1pt,
    linecolor=black,
    innerlinecolor=black,
    middlelinecolor=black,
    outerlinecolor=black,
    roundcorner=10pt,
    leftmargin=.05\textwidth,
    rightmargin=.05\textwidth,
    skipabove=\baselineskip,  %skip above the frame
    skipbelow=0.25\baselineskip, %skip between the frame and the caption
    innerleftmargin=10pt,    
    innerrightmargin=10pt,
    innertopmargin=10pt,
    innerbottommargin=10pt]%
    \nopagebreak
   \caption@freeze %"freeze" caption related commands
  }{%
  \end{mdframed}%
  \nopagebreak
  \caption@defrost %typeset caption, if necessary
}
\makeatother

\crefname{boxx}{box}{boxes}
\crefname{req}{requirement}{requirements}

\begin{document}

\chapter{Chapter}
\noindent This is a reference to \cref{box:one}.

\begin{boxx}
\lipsum[2]
\begin{enumerate}[label=\textbf{Req. \arabic*},ref=Req. \arabic*,leftmargin=*]
\item one\label{req:one}
\item two generalised.
\end{enumerate}
\caption[shorter]{This is a box with text}\label{box:one}
\end{boxx}

\noindent \lipsum[1-2]
Some more text, ref to item: \cref{req:one}

\begin{boxx}
\begin{java}
class HelloWorldApp
{
    public float pi = 3.14159;
    public int i = 0;

    public static void main(String[] args)
    {
        System.out.println("Hello World!"); //Display the string
    }
}
\end{java}
\caption{This is a box with Java code}\label{box:two}
\end{boxx}


\noindent Double uppercase reference: \Cref{box:one,box:two}.


\noindent \lipsum[3]

\pagebreak
\listofboxxs


\end{document}
Matthias
  • 4,051