% \iffalse meta-comment
%
% Copyright (C) 2025 Fabian Fuchs
%
% This file may be distributed and/or modified
%
% 1. under the LaTeX Project Public License and/or
% 2. under the GNU Public License.
%
% The latest version of the LaTeX Project Public 
% License can be found under:
%
% http://www.latex-project.org/lppl.txt
%
%
% \fi
%
% \iffalse
%<package>\NeedsTeXFormat{LaTeX2e}[2023-11-01]
%<package>\ProvidesPackage{beamer-varbox}
%<package> [2025/09/11 A package providing beamer boxes with variable size corners]
%
%<*driver>
\documentclass{ltxdoc}
\usepackage{beamer-varbox}
\EnableCrossrefs
\CodelineIndex
\RecordChanges
\begin{document}
\DocInput{beamer-varbox.dtx}
\end{document}
%</driver>
% \fi
%
% \changes{v1.0}{2025-09-11}{Initial version}
%
% \GetFileInfo{beamer-varbox.sty}
%
% \DoNotIndex{⟨list of control sequences⟩}
% \NewDocElement{Opt}{option}
%
% \title{The \textsf{beamer-varbox} package\thanks{This document
% corresponds to \textsf{beamer-varbox}~\fileversion,
% dated \filedate.}}
% \author{Fabian Fuchs \\ \texttt{fabian.m.fuchs@gmail.com}}
%
% \maketitle
%
% \begin{abstract}
% A package providing beamer boxes with variable size corners.
% \end{abstract}
%
% \section{Usage}
% Loading the package provides the \texttt{variable rounded} predefined option for
% the beamer elements \texttt{block begin}, \texttt{block alerted begin}, 
% \texttt{block example begin}, \texttt{block end}, \texttt{block alerted end}, and 
% \texttt{block example end} and sets them as default. (It is assumed that if you include the 
% package, you want the modified blocks)
% 
% \section{Options}
% 
% \DescribeOpt{cornerpercent}
% The package has one option, |cornerpercent|, that describes the scale of corner arc
% relative to the standard rounded predefined option provided by the beamer class.
% It is a keyword option that takes values between 0 and 1 (inclusive) and can be called either
% when including the package as\\
% \vspace{1ex}
% |\usepackage| [cornerpercent=⟨\textit{value}⟩] \{beamer-varbox\}\\
% \vspace{1ex}
% or when setting the template manually as, e.g.,\\
% \vspace{1ex}
% |\setbeamertemplate| \marg{element name} [variable rounded] [cornerpercent=⟨\textit{value}⟩]\\
% \vspace{1ex}
%
% \MaybeStop{\PrintIndex}
%
% \section{Implementation}

%    \begin{macrocode}
% Check that beamer class is loaded
% 
\@ifclassloaded{beamer}{}{%
    \PackageError{beamer-varbox}{%
      This package needs the beamer class.\MessageBreak
      To use this package, load the beamer class.
    }{%
      The package could not be loaded, because it needs\MessageBreak
      beamer class to function.
    }%
    \endinput
}


% Require xkeyval to do "modern" package keyval handling
\RequirePackage{xkeyval}

\DeclareOptionX{cornerpercent}[0.3]{\def\beamer@cornerpercentdefault{#1}}
\ExecuteOptionsX{cornerpercent=0.3}
\ProcessOptionsX\relax

% Define 0 to compare against
\def\bmb@zero{0}

%
% Define used keys
%
\define@key{beamerboxes}{scheme}{\def\bmb@upper{@scheme upper #1}\def\bmb@lower{@scheme lower #1}}
\define@key{beamerboxes}{upper}{\def\bmb@upper{#1}}
\define@key{beamerboxes}{lower}{\def\bmb@lower{#1}}
\define@key{beamerboxes}{width}{\edef\bmb@width{#1}}
\define@key{beamerboxes}{shadow}[true]{\csname bmb@shadow#1\endcsname}
\define@key{beamerboxes}{cornerpercent}{\def\bmb@cornerpercent{#1}}

% Define neeeded variables
\newif\ifbmb@shadow
\newbox\bmb@box
\newbox\bmb@colorbox
\newdimen\bmb@boxwidth
\newdimen\bmbboxheight
\newdimen\bmb@prevheight
\newdimen\bmb@temp
\newdimen\bmb@dima
\newdimen\bmb@dimb
\newdimen\bmb@dimc
\newdimen\bmb@prevheight
\newdimen\bmb@supportcorner
\newdimen\bmb@initstart
\newdimen\bmb@advance

%
% The below is adapted from the beamer package
% files beamerbaseboxes.sty and beamerbaseauxtemplates.sty.
% Authors of those files are:
% Till Tantau, Vedran Mileti\'c, Joseph Wright, 
% Louis Stuart, and samcarter.
% Thanks for the work!!
% 
\newcommand\beamerboxesvariablerounded[2][]{%
  \global\let\beamer@firstlineitemizeunskip=\relax%
  \vbox\bgroup%
  \setkeys{beamerboxes}{upper=block title,lower=block body,width=\textwidth,shadow=false,cornerpercent=\beamer@cornerpercentdefault}%
  \setkeys{beamerboxes}{#1}%
  {%
    \usebeamercolor{\bmb@lower}%
    \globalcolorstrue%
    \colorlet{lower.bg}{bg}%
  }%
  {%
    \usebeamercolor{\bmb@upper}%
    \globalcolorstrue%
    \colorlet{upper.bg}{bg}%
  }%

  %
  % Typeset head
  %
  \vskip4bp
  \setbox\bmb@box=\hbox{%
    \begin{minipage}[b]{\bmb@width}%
      \usebeamercolor[fg]{\bmb@upper}%
      #2%
    \end{minipage}}%
  \ifdim\wd\bmb@box=0pt%
    \setbox\bmb@box=\hbox{}%
    \ht\bmb@box=1.5pt%
    \bmb@prevheight=-4.5pt%
  \else%
    \wd\bmb@box=\bmb@width%
    \bmb@temp=\dp\bmb@box%
    \ifdim\bmb@temp<1.5pt%
      \bmb@temp=1.5pt%
    \fi%
    \setbox\bmb@box=\hbox{\raise\bmb@temp\hbox{\box\bmb@box}}%
    \dp\bmb@box=0pt%
    \bmb@prevheight=\ht\bmb@box%
  \fi%
  %
  %
  %
  \ifdim\bmb@cornerpercent pt >1pt
  \PackageError{beamer-varbox}{%
      The key cornerpercent is above 1.\MessageBreak
      The key is allowed to take values in between 0 and 1 (inclusive)%
    }{%
      cornerpercent is allowed to be between 0 and 1 (inclusive)%
    }%
  \fi
  %
  % Check if the corners should be sharp
  %
  \if\bmb@cornerpercent\bmb@zero
  \bmb@temp=\bmb@width%
  \bmb@dima=\bmb@temp\advance\bmb@dima by8bp%
  \bmb@dimc=-\ht\bmb@box\advance\bmb@dimc by-2pt%
  \hbox{%
    \begin{pgfpicture}{0bp}{+-\ht\bmb@box}{0bp}{+-\ht\bmb@box}
      \ifdim\wd\bmb@box=0pt%
        \color{lower.bg}%  
        \pgfsetfillopacity{0}      
      \else%
        \color{upper.bg}%
      \fi%
      \pgfpathqmoveto{-4bp}{\bmb@dimc}%
      \pgfpathqlineto{-4bp}{3bp}%
      \pgfpathqlineto{\bmb@dima}{3bp}%
      \pgfpathqlineto{\bmb@dima}{\bmb@dimc}%
      \pgfsetlinewidth{1.5pt}
      \pgfusepath{fill,stroke}
    \end{pgfpicture}%
    \copy\bmb@box%
  }%
  \else
  %
  % Calculate dimensions for adjusted corner
  %
  \bmb@supportcorner=\dimexpr\bmb@cornerpercent\dimexpr1.8bp\relax\relax%
  \bmb@initstart=\dimexpr 4bp-\bmb@cornerpercent\dimexpr4bp\relax\relax%
  \bmb@advance=\dimexpr \bmb@initstart+\bmb@cornerpercent\dimexpr2.2bp\relax\relax%
  % Calculate aux sizes
  \bmb@temp=\bmb@width%
  \bmb@dima=\bmb@temp\advance\bmb@dima by\bmb@advance%
  \bmb@dimb=\bmb@temp\advance\bmb@dimb by4bp%
  \bmb@dimc=-\ht\bmb@box\advance\bmb@dimc by-2pt%
  \hbox{%
    \begin{pgfpicture}{0bp}{+-\ht\bmb@box}{0bp}{+-\ht\bmb@box}
      \ifdim\wd\bmb@box=0pt%
        \color{lower.bg}%  
        \pgfsetfillopacity{0}      
      \else%
        \color{upper.bg}%
      \fi%
      \pgfpathqmoveto{-4bp}{\bmb@dimc}
      \pgfpathlineto{\pgfpoint{-4bp}{-1bp+\bmb@initstart}}
      \pgfpathcurveto% Upper left corner
      {\pgfpoint{-4bp}{3bp-\bmb@supportcorner}}%
      {\pgfpoint{-4bp+\bmb@supportcorner}{3bp}}%
      {\pgfpoint{-\bmb@initstart}{3bp}}%
      \pgfpathlineto{\pgfpoint{\bmb@temp+\bmb@initstart}{3bp}}
      \pgfpathcurveto% Upper right corner
      {\pgfpoint{\bmb@dima}{3bp}}%
      {\pgfpoint{\bmb@dimb}{3bp-\bmb@supportcorner}}%
      {\pgfpoint{\bmb@dimb}{-1bp+\bmb@initstart}}%
      \pgfpathqlineto{\bmb@dimb}{-1bp}%
      \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dimc}}
      \pgfsetlinewidth{1.5pt}
      \pgfusepath{fill,stroke}
    \end{pgfpicture}%
    \copy\bmb@box%
  }%
  \fi % of sharp corner check
  \nointerlineskip%
  \vskip-1pt%
  \ifdim\wd\bmb@box=0pt%
  \else%
    \vskip3pt%
  \fi%
  \setbox\bmb@colorbox=\hbox{{\pgfpicturetrue\pgfsetcolor{lower.bg}}}%
  \setbox\bmb@box=\hbox\bgroup\begin{minipage}[b]{\bmb@width}%
    \vskip2pt%
    \usebeamercolor[fg]{\bmb@lower}%
    \colorlet{beamerstructure}{upper.bg}%
    \colorlet{structure}{upper.bg}%
  }



\def\endbeamerboxesvariablerounded{%
  \end{minipage}\egroup%
  \bmb@temp=\dp\bmb@box%
  \advance\bmb@temp by.5pt%
  \setbox\bmb@box=\hbox{\raise\bmb@temp\hbox{\box\bmb@box}}%
  \dp\bmb@box=0pt%
  \bmb@boxwidth=\bmb@width%
  \bmb@boxheight=\ht\bmb@box%
  \advance\bmb@boxheight by4bp%
  \advance\bmb@boxheight by\bmb@prevheight%
  \ifbmb@shadow%
    \xdef\beamer@storecolorhook{\beamer@colorhook}
    \xdef\beamer@colorhook{}
    \pgfdeclareradialshading{bmb@shadowball}{\pgfpointorigin}
    {%
      color(0bp)=(pgftransparent!50);
      color(4bp)=(pgftransparent!100)
    }%
    \pgfdeclareradialshading{bmb@shadowballlarge}{\pgfpointorigin}
    {%
      color(0bp)=(pgftransparent!0);
      color(8bp)=(pgftransparent!100)
    }%
    \pgfdeclarehorizontalshading{bmb@shadowhorz\the\bmb@boxheight}{\bmb@boxheight-5.5bp}
    {%
      color(0bp)=(pgftransparent!0);
      color(8bp)=(pgftransparent!100)
    }%
    \pgfdeclareverticalshading{bmb@shadowvert\the\bmb@boxwidth}{\bmb@boxwidth-4bp}
    {%
      color(0bp)=(pgftransparent!100);
      color(8bp)=(pgftransparent!0)
    }%
    \begingroup%
      \selectcolormodel{gray}
      \pgfdeclarefading{bmb@shadowmask\the\bmb@boxwidth\the\bmb@boxheight}
      {%
        \begin{pgfpicture}
          \pgftext[at=\pgfpoint{4bp}{4bp}]{\pgfuseshading{bmb@shadowball}}% bottom left shadow
          \ifdim\bmb@boxheight>9.5bp%
            \pgftext[at=\pgfpoint{\bmb@boxwidth}{8bp}]{\pgfuseshading{bmb@shadowballlarge}}% bottom right shadow
            \pgftext[at=\pgfpoint{\bmb@boxwidth+4bp}{\bmb@boxheight+2bp}]{\pgfuseshading{bmb@shadowball}}% top right shadow
            \pgftext[base, at=\pgfpoint{\bmb@boxwidth+4bp}{7.5bp}]{\pgfuseshading{bmb@shadowhorz\the\bmb@boxheight}}% right edge shadow
          \else%
            \pgftext[at=\pgfpoint{\bmb@boxwidth}{4bp}]{\pgfuseshading{bmb@shadowball}}% right shadow
          \fi%
          \pgftext[left, at=\pgfpoint{4bp}{4bp}]{\pgfuseshading{bmb@shadowvert\the\bmb@boxwidth}}% bottom edge
          %
          % clipping is needed because shadow is typeset on top of box
          \begin{pgfscope}
            \pgfsetcolor{beamer@safeblack}
            \pgfpathrectangle{\pgfpoint{4bp}{8.1bp}}{\pgfpoint{\bmb@boxwidth}{\bmb@boxheight-2bp}}
            \pgfusepath{fill}
          \end{pgfscope}
        \end{pgfpicture}%
        \hskip4bp%      
      }%
    \endgroup%
    
  \fi%
  %
  % Check if the corners should be sharp
  %
  \if\bmb@cornerpercent\bmb@zero
  \bmb@temp=\bmb@width%
  \bmb@dima=\bmb@temp\advance\bmb@dima by8bp%
  \bmb@dimc=\ht\bmb@box
  \hbox{%
    \begin{pgfpicture}{0bp}{0bp}{0bp}{0bp}
      \ifbmb@shadow%
        \begin{pgfscope}
          \pgfpathrectangle{\pgfpoint{0bp}{-7bp}}
            {\pgfpoint{\bmb@boxwidth+8bp}{\bmb@boxheight+6bp}}
          \pgfsetfading{bmb@shadowmask\the\bmb@boxwidth\the\bmb@boxheight}{%
            \pgftransformshift{\pgfpoint{0.5\bmb@boxwidth+6bp}{0.5\bmb@boxheight-4bp}}}
          \pgfusepath{fill}
        \end{pgfscope}
      \fi%
      \unhbox\bmb@colorbox%
      \pgfpathqmoveto{-4bp}{\bmb@dimc}%
      \pgfpathqlineto{-4bp}{-3bp}%
      \pgfpathqlineto{\bmb@dima}{-3bp}%
      \pgfpathqlineto{\bmb@dima}{\bmb@dimc}%
      \pgfsetlinewidth{1.5pt}
      \pgfusepath{stroke}
    \end{pgfpicture}%
    \box\bmb@box%
  }%
  \else
  \bmb@temp=\bmb@width%
  \bmb@dima=\bmb@temp\advance\bmb@dima by\bmb@advance%
  \bmb@dimb=\bmb@temp\advance\bmb@dimb by4bp%
  \hbox{%
    \begin{pgfpicture}{0bp}{0bp}{0bp}{0bp}
      \ifbmb@shadow%
        \begin{pgfscope}
          \pgfpathrectangle{\pgfpoint{0bp}{-7bp}}
            {\pgfpoint{\bmb@boxwidth+8bp}{\bmb@boxheight+6bp}}
          \pgfsetfading{bmb@shadowmask\the\bmb@boxwidth\the\bmb@boxheight}{%
            \pgftransformshift{\pgfpoint{0.5\bmb@boxwidth+6bp}{0.5\bmb@boxheight-4bp}}}
          \pgfusepath{fill}
        \end{pgfscope}
      \fi%
      \unhbox\bmb@colorbox%
      \bmb@dimc=\ht\bmb@box
      \pgfpathqmoveto{-4bp}{\bmb@dimc}
      \pgfpathlineto{\pgfpoint{-4bp}{1bp-\bmb@initstart}}
      \pgfpathcurveto% Lower left corner
      {\pgfpoint{-4bp}{-3bp+\bmb@supportcorner}}%
      {\pgfpoint{-4bp+\bmb@supportcorner}{-3bp}}%
      {\pgfpoint{-\bmb@initstart}{-3bp}}%
      \pgfpathlineto{\pgfpoint{\bmb@temp+\bmb@initstart}{-3bp}}
      \pgfpathcurveto% Lower right corner
      {\pgfpoint{\bmb@dima}{-3bp}}%
      {\pgfpoint{\bmb@dimb}{-3bp+\bmb@supportcorner}}%
      {\pgfpoint{\bmb@dimb}{1bp-\bmb@initstart}}%
      \pgfpathqlineto{\bmb@dimb}{-1bp}%
      \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dimc}}
      \pgfsetlinewidth{1.5pt}
      \pgfusepath{stroke}
    \end{pgfpicture}%
    \box\bmb@box%
  }%
  \fi% of corner check
  \ifbmb@shadow%
    \vskip4bp minus 2bp%
  \else%
    \vskip2bp%
  \fi%
  \egroup% of \vbox\bgroup
  \ifbmb@shadow%
    \xdef\beamer@colorhook{\beamer@storecolorhook}
  \fi
}


\defbeamertemplate*{block begin}{variable rounded}[1][shadow=false]%
{%
  \par\vskip\medskipamount%
  \begin{beamerboxesvariablerounded}[upper=block title,lower=block body,#1]%
    {\raggedright\usebeamerfont*{block title}\insertblocktitle}%
    \raggedright%
    \usebeamerfont{block body}%
}%

\defbeamertemplate*{block end}{variable rounded}%
{%
  \end{beamerboxesvariablerounded}\vskip\smallskipamount
}%

\defbeamertemplate*{block alerted begin}{variable rounded}[1][shadow=false]
{%
  \par\vskip\medskipamount%
  \begin{beamerboxesvariablerounded}[upper=block title alerted,lower=block body alerted,#1]%
    {\raggedright\usebeamerfont*{block title alerted}\insertblocktitle}%
    \raggedright%
    \usebeamerfont{block body alerted}%
}%
\defbeamertemplate*{block alerted end}{variable rounded}[1][]
{
  \end{beamerboxesvariablerounded}\vskip\smallskipamount
}

\defbeamertemplate*{block example begin}{variable rounded}[1][shadow=false]
{%
  \par\vskip\medskipamount%
  \begin{beamerboxesvariablerounded}[upper=block title example,lower=block body example,#1]
    {\raggedright\usebeamerfont*{block title example}\insertblocktitle}%
    \raggedright%
    \usebeamerfont{block body example}%
}%
\defbeamertemplate*{block example end}{variable rounded}[1][]
{\end{beamerboxesvariablerounded}\vskip\smallskipamount}
%    \end{macrocode}
%
% \Finale
\endinput