6

I need to insert a quite long Matlab code in a presentation (for a course on numerical methods) and I would like to insert it using a rolling window, is it possible to do something like this in beamer? I sniffed a little the internet on what it says on this topic but I didnt find a smart solution.

  • What's a rolling window? – Ignasi May 12 '16 at 19:10
  • @Ignasi I understand it as a window inside the slide with an smaller size than the slide (of course) where you can show a piece of that long code and also you can move through that long code with an scrolling vertical bar (at least). – Aradnix May 12 '16 at 19:25
  • Yes, sorry, I meant exactly what Aradnix said. I think that the precise english word is "scrolling window". – AlmostSureUser May 13 '16 at 7:16
9

Here is a scrolling window with some Octave code (which is similar to Matlab) picked at random from my Octave installation.

enter image description here

The scrolling widget is based on the animate package. (And thus requires AR for viewing.)

LaTeX package minted + Pygments are used as code prettyfier which require Python.

Scroll buttons are put on top and below the code window to step through the code by mouse click, or to go to start or end by [shift]+mouse click.

Animated scrolling is started by clicking into the code, it is paused by pressing the mouse button inside the code. Moving the mouse pointer out while keeping the button pressed pauses it permanently.

\documentclass{beamer}

\usepackage{minted}   % code prettyfier
\usepackage{xsavebox} % file-size-efficient saveboxes
\usepackage{animate}  % for animated scrolling
\usepackage{MnSymbol} % \triangle, \triangledown for scroll buttons
\usepackage{media9}   % buttons

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% \smoothScroll[<animate opts>]    % autoplay,loop,... (see: texdoc animate)
%              {<xsavebox id>}
%              {<viewport height>}
%              {<steps>}           % scrolling granularity
%              {<steps per sec>}   % while playing; >25 doesn't make sense
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand\smoothScroll[5][]{%
  \savebox\myMeasBox{\xusebox{#2}}%
  \edef\mywd{\the\wd\myMeasBox}%
  \edef\myht{\the\ht\myMeasBox}%
  \edef\mytht{\the\dimexpr\ht\myMeasBox+\dp\myMeasBox\relax}%
  \edef\portht{\the\dimexpr#3\relax}%
  \begin{animateinline}[#1,label={#2},width=\mywd,height=\portht]{#5}%
    \multiframe{#4}{%
      dRaiseLen=\the\dimexpr-\myht+\portht\relax+\the\dimexpr(\mytht-\portht)/%
                \numexpr#4-1\relax\relax
    }{%
      \begin{minipage}[b][\portht][b]{\mywd}%
        \raisebox{\dRaiseLen}[0pt][0pt]{\xusebox{#2}}%
      \end{minipage}%
    }%
  \end{animateinline}%
}
\newsavebox\myMeasBox % for measuring purposes
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% \topScrollButton{<xsavebox id>}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand\topScrollButton[1]{%
  \mediabutton[
    jsaction={
      if(event.shift){anim['#1'].pause();anim['#1'].frameNum=0;}
      else try{anim['#1'].frameNum--}catch(e){}
    }
  ]{\fboxsep=0pt\framebox[\widthof{\xusebox{#1}}][c]{%
    \tiny\strut\raisebox{-0.2\height}{$\triangle\triangle\triangle$}}%
  }%
}  
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% \botScrollButton{<xsavebox id>}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand\botScrollButton[1]{%
  \mediabutton[
    jsaction={
      if(event.shift){anim['#1'].pause();anim['#1'].frameNum=anim['#1'].numFrames-1;}
      else try{anim['#1'].frameNum++}catch(e){}
    }
  ]{\fboxsep=0pt\framebox[\widthof{\xusebox{#1}}][c]{%
    \tiny\strut\raisebox{0.1\height}{$\triangledown\triangledown\triangledown$}}%
  }%
}  
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{document}

\begin{frame}{Octave code: \color{black}\Verb+demo.m+}

% typeset code into xsavebox `SomeCode'  
\begin{xlrbox}{SomeCode}%
  \begin{minipage}{\linewidth}%  
    \inputminted[fontsize=\scriptsize]{octave}{demo.m}%
  \end{minipage}%  
\end{xlrbox}%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\topScrollButton{SomeCode}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% scrolling widget
\smoothScroll{SomeCode}{0.75\textheight}{500}{25}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\raisebox{2ex}{\botScrollButton{SomeCode}}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\end{frame}
\end{document}
  • Thanks, it is exactly what I am looking for. While compiling it gives me this error: invoke latex with the -shell -escape flag any ideas? I have tried to change the compilation command (I use TeXShop for Mac) but I was unsuccessful. – AlmostSureUser May 19 '16 at 7:36
  • 2
    @AlmostSureUser I usually run latex and friends directly on the command line. Make sure your editor is configured to run pdflatex --shell-escape ... (no space between --shell and -escape. And I hope you have Python installed on your Mac. – AlexG May 19 '16 at 7:43
  • I am looking for slider bar [exactly the same as seen above in latex source code sample area] on the right side of the code display area! Have been trying this with lstlisting of a long Matlab code but failed :( – Khaaba Mar 11 '18 at 15:26
  • PDF is not HTML, sorry. Sliders as shown in web browsers are not available in PDF. The best what you can get is already shown in the animation of my answer: 2 longish buttons, one above, one below the scrolling window. – AlexG Mar 13 '18 at 11:19
  • I am grateful to you for this wonder code in the answer above. However, I wanted blocks of code below, block after another, to slide up along side their full output image in the teaching! Sliding up line by line or auto mode has little disadvantage or I need to change the explaination style if there is no other available. Thanks a lot once again for the wonderful code! – Khaaba Mar 14 '18 at 4:41
3

For those who are interested for a listings scrolling window environment. I wrapped the AlexGs' code scroll commands into a new listings environment called codescroll. All you have to do it to provide the environment with:

  • Listing options [optional]
  • A unique xsavebox id
  • The number of the lines of your code
  • The view-port height in lines of code

The advantage of the listings package is that you can customize it for any programming language and use your own style. In the following example I created my own C++ style and I passed it to the codescroll environment I created.

\documentclass{beamer}

\usepackage{xsavebox} % file-size-efficient saveboxes
\usepackage{animate}  % for animated scrolling
\usepackage{MnSymbol} % \triangle, \triangledown for scroll buttons
\usepackage{media9}   % buttons
\usepackage{xintexpr} % calculate expressions

% Code colors (Irrelevant from the presentation color theme!)
\definecolor{codemaincolor}{RGB}{0, 0, 0}
\definecolor{codebackgroundcolor}{RGB}{255, 255, 255}
\definecolor{codekeywordcolor}{RGB}{0, 0, 255}
\definecolor{codestringcolor}{RGB}{163, 21, 21}
\definecolor{codecommentcolor}{RGB}{39, 139, 39}
\definecolor{codeusertypecolor}{RGB}{43, 145, 175}

\usepackage{listings}
\usepackage{lstautogobble}
\lstset {
  basicstyle={\scriptsize \ttfamily \color{codemaincolor}},
  backgroundcolor=\color{codebackgroundcolor},
  autogobble = true,
  tabsize = 2,
  xleftmargin=0pt,
  xrightmargin=0pt,
  aboveskip=0pt, % \medskipamount,
  belowskip=0pt, % \medskipamount,
  literate={\ \ }{{\ }}1
}
% Code C++ style
\lstdefinestyle{C++} {
  language=C++,
  otherkeywords = {final, override, noexcept},
  keywordstyle = {\color{codekeywordcolor}},
  stringstyle = {\color{codestringcolor}},
  commentstyle = {\color{codecommentcolor}\em},
  % Class and types highlighting
  classoffset=1, % starting new class
  morekeywords={vector, ostream, unique_ptr, shared_ptr, T, device_t, abstract_device, device_one, device_two, device_three, executable_device, measurable_device, my_device, concept_t, model, device_one_model, device_two_model, sensor_t, history_t},
  keywordstyle=\color{codeusertypecolor},
  classoffset=0,
}

% \smoothScroll[<animate opts>]{<xsavebox id>}{<viewport height>}{<steps>}{<steps per sec>}
\newcommand{\smoothScroll}[5][]{%
  \savebox\measBox{\xusebox{#2}}%
  \edef\boxwd{\the\wd\measBox}%
  \edef\boxht{\the\ht\measBox}%
  \edef\boxtht{\the\dimexpr\ht\measBox+\dp\measBox\relax}%
  \edef\portht{\the\dimexpr#3\relax}%
  \begin{animateinline}[#1,label={#2},width=\boxwd,height=\portht]{#5}%
    \multiframe{#4}{%
      dRaiseLen=\the\dimexpr-\boxht+\portht\relax+\the\dimexpr(\boxtht-\portht)/%
                \numexpr#4-1\relax\relax
    }{%
      \begin{minipage}[b][\portht][b]{\boxwd}%
        \raisebox{\dRaiseLen}[0pt][0pt]{\xusebox{#2}}%
      \end{minipage}%
    }%
  \end{animateinline}%
}
\newsavebox\measBox % for measuring purposes

% \topScrollButton{<xsavebox id>}{<step>}
\newcommand{\topScrollButton}[2]{%
  \mediabutton[
    jsaction={
      if(event.shift){anim['#1'].pause();anim['#1'].frameNum=0;}
      else try{anim['#1'].frameNum-=#2}catch(e){anim['#1'].frameNum=0;}
    }
  ]{\fboxsep=0pt\framebox[\widthof{\xusebox{#1}}][c]{%
    \tiny\strut\raisebox{-0.2\height}{$\triangle\triangle\triangle$}}%
  }%
}

% \botScrollButton{<xsavebox id>}{<step>}
\newcommand{\botScrollButton}[2]{%
  \mediabutton[
    jsaction={
      if(event.shift){anim['#1'].pause();anim['#1'].frameNum=anim['#1'].numFrames-1;}
      else try{anim['#1'].frameNum+=#2}catch(e){anim['#1'].frameNum=anim['#1'].numFrames-1;}
    }
  ]{\fboxsep=0pt\framebox[\widthof{\xusebox{#1}}][c]{%
    \tiny\strut\raisebox{0.1\height}{$\triangledown\triangledown\triangledown$}}%
  }%
}

% \begin{codescroll}[<lstlisting opts>]{<xsavebox id>}{<total lines>}{<viewport lines>}
\lstnewenvironment{codescroll}[4][style=C++]
{\lstset{#1}\xlrbox{#2}\noindent\minipage{\linewidth}}
{\endminipage\endxlrbox%
\def\lnsperframe{28}% max lines without the buttons you have to change this value for different margins, beamer themes etc.
\def\lnht{5}% height of each line
\def\lnspersec{3}% scroll number of lines per second
\def\htpercentage{\xintthefloatexpr #4 / \lnsperframe \relax}% calculate the height of the scroll area
\def\steps{\xintexpr #3 - #4 + 1 \relax}% steps needed to go from the first to last line
\def\viewportheight{\xinttheiexpr (#3 + 1)  * \lnht \relax}% total height of the viewport
\def\btnstep{\xintthefloatexpr \viewportheight / \steps \relax}% step to in(dec)crease when press the buttons
\def\stepspersec{\xintthefloatexpr \lnspersec * \btnstep \relax}% scroll speed
\topScrollButton{#2}{\btnstep}\\%
\smoothScroll{#2}{\htpercentage\textheight}{\viewportheight}{\stepspersec}\\%
\raisebox{2ex}{\botScrollButton{#2}{\btnstep}}%
}

\begin{document}

\begin{frame}[t,fragile]
  % typeset code into xsavebox `code1'
  \begin{codescroll}[style=C++]{code1}{43}{24}
    template<typename T>
    void trigger(const T& d, ostream& out)
    { d.trigger(out); }

    class device_t
    {public:
        template<typename T>
        device_t(T d) :
            self_(make_unique<model<T>>(move(d))) {}

        friend void trigger(const device_t& d, ostream& out)
        { trigger(d.self_, out); }
     private:
        struct concept_t {
            virtual ~concept_t() = default;
            virtual void trigger_(ostream& out) const = 0;
        };
        template<typename T>
        struct model final : concept_t{
            model(T d) : data_(move(d)) {}
            void trigger_(ostream out) const override
            { trigger(data_, out); }
            T data_;
        };
        shared_ptr<const concept_t> self_;
    };

    using sensor_t = vector<device_t>;

    void trigger(const sensor_t& s, ostream& out)
    { out << "Sensor triggering...\n";
        for (const auto& d : s) trigger(d, out);
        out << "Sensor triggered!\n";
    }

    using history_t = vector<sensor_t>;

    void commit(history_t& x)
    { assert(x.size()); x.push_back(x.back()); }
    void undo(history_t& x )
    { assert(x.size()); x.pop_back(); }
    sensor_t& current(history_t& x)
    { assert(x.size()); return x.back(); }
  \end{codescroll}
\end{frame}

\begin{frame}[t,fragile]{C++ code}
% typeset code into xsavebox `code2'
  \begin{codescroll}[style=C++]{code2}{51}{21}
        template<typename T>
        void trigger(const T& d, ostream& out)
        { d.trigger(out); }

        class device_t
        {public:
            template<typename T>
            device_t(T d) :
                self_(make_unique<model<T>>(move(d))) {}

            device_t(device_t d) :
                self_(d.self_->copy()) {}
            device_t(device_t&&) noexcept = default;
            device_t& operator=(const device_t& d)
            { return *this = device_t(d); }
            device_t& operator=(device_t&&) noexcept = default;

            friend void trigger(const device_t& d, ostream& out)
            { trigger(d.self_, out); }
         private:
            struct concept_t {
                virtual ~concept_t() = default;
                unique_ptr<concept_t> copy_() const = 0;
                virtual void trigger_(ostream& out) const = 0;
            };
            struct device_two_model final : concept_t{
                device_two_model(@device_two@ d) : data_(move(d)) {}
                unique_ptr<concept_t> copy_() const override
                { return make_unique<device_two_model>(*this); }
                void trigger_(ostream out) const override
                { trigger(data_, out); }
                @device_two@ data_;
            };
            struct device_one_model final : concept_t{
                device_one_model(@device_one@ d) : data_(move(d)) {}
                unique_ptr<concept_t> copy_() const override
                { return make_unique<device_one_model>(*this); }
                void trigger_(ostream out) const override
                { trigger(data_, out); }
                @device_one@ data_;
            };
            unique_ptr<concept_t> self_;
        };

        using sensor_t = vector<device_t>;

        void trigger(const sensor_t& s, ostream& out)
        { out << "Sensor triggering...\n";
            for (const auto& d : s) trigger(d, out);
            out << "Sensor triggered!\n";
        }
  \end{codescroll}
\end{frame}
\end{document}

As you see the usage of the codescroll environment is straight forward.

% \begin{codescroll}[<lstlisting opts>]{<xsavebox id>}{<total lines>}{<viewport lines>}

I hope that solution to help all kinds of programmers. enter image description here

2

Better use [allowframebreaks] and let the code break into various slides because scrollers generate problems, for example they only work for some pdf viewers.

\begin{frame}[fragile,allowframebreaks]{Newton Raphson Code}
\lstinputlisting[language=Matlab]{lfnewton.m}

Note: here I have used the Matlab prettifier package in the form mentioned below:

\usepackage[framed,numbered]{matlab-prettifier}
  • Why the down vote? – DG' Oct 26 '18 at 17:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.