%% % \iffalse %<*copyright> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% acrosort package, %% %% Copyright (C) 2006--2020 D. P. Story %% %% dpstory@acrotex.net %% %% storyd@nwfsc.edu %% %% %% %% This program can redistributed and/or modified under %% %% the terms of the LaTeX Project Public License %% %% Distributed from CTAN archives in directory %% %% macros/latex/base/lppl.txt; either version 1 of the %% %% License, or (at your option) any later version. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % %\NeedsTeXFormat{LaTeX2e} %\ProvidesPackage{acrosort} % [2020/06/17 v1.6.1 AcroSort (dps)] %<*driver> \documentclass{ltxdoc} \usepackage[colorlinks,hyperindex=false]{hyperref} \usepackage{fancyvrb} %\def\texorpdfstring#1#2{#1} %\pdfstringdefDisableCommands{\let\\\textbackslash} \OnlyDescription % comment out for implementation details \EnableCrossrefs \CodelineIndex \RecordChanges \InputIfFileExists{aebdocfmt.def}{\PackageInfo{web}{Inputting aebdocfmt.def}} {\def\IndexOpt{\DescribeMacro}\def\IndexKey{\DescribeMacro}\let\setupFullwidth\relax \PackageInfo{web}{aebdocfmt.def cannot be found}} \EnableCrossrefs \CodelineIndex \RecordChanges \begin{document} \bgroup\ttfamily \gdef\brpr#1{\char123\relax#1\char125\relax}\egroup \let\darg\brpr \let\env\texttt \let\opt\texttt \let\app\textsf \def\visispace{\symbol{32}} \def\ameta#1{\ensuremath{\langle\textit{\texttt{#1}}\rangle}} \def\meta#1{\textsl{\texttt{#1}}} \def\SUB#1{\ensuremath{{}_{\mbox{\scriptsize\ttfamily#1}}}} \def\ltag{<}\def\rtag{>} \def\EXCL{!} \let\app\textsf\let\pkg\textsf \GetFileInfo{acrosort.sty} \title{The \textsf{acrosort} Package} \author{D. P. Story\\ Email: \texttt{dpstory@acrotex.net}} \date{processed \today} \maketitle \tableofcontents \let\Email\texttt \DocInput{acrosort.dtx} \IfFileExists{\jobname.ind}{\newpage\setupFullwidth\par\PrintIndex}{\paragraph*{Index} The index goes here.\\Execute \texttt{makeindex -s gind.ist -o acrosort.ind acrosort.idx} on the command line and recompile \texttt{acrosort.dtx}.} \IfFileExists{\jobname.gls}{\PrintChanges}{\paragraph*{Change History} The list of changes goes here.\\Execute \texttt{makeindex -s gglo.ist -o acrosort.gls acrosort.glo} on the command line and recompile \texttt{acrosort.dtx}.} \end{document} % % \fi % \MakeShortVerb{|} % \InputIfFileExists{aebdonotindex.def}{\PackageInfo{web}{Inputting aebdonotindex.def}} % {\PackageInfo{web}{cannot find aebdonotindex.def}} % \DoNotIndex{\DPSIndxList,\g@addto@macro,\divide,\box,\setbox,\x,\y,\z} % % \section{Introduction} % \pkg{acrosort} is a novelty {\LaTeX} package for embedding a series of tiled % images of a picture. The tiled images are randomly arranged, then resorted % before the user's eyes using a bubble sort. % % This new version of \pkg{acrosort}, dated 2020/06/02 or later, supports all % common workflows: \app{pdflatex}, \app{lualatex}, \app{xelatex}, and % \app{dvips\,\texttt{->}\,distiller}. % % The \pkg{graphicx}, \pkg{eforms}, and \pkg{icon-appr} packages are % automatically input by \textsf{acrosort}. When the workflow % \app{dvips\,\texttt{->}\,distiller} is used, the package \pkg{aeb\_pro} is required. % % For the first time, \emph{multiple tiled bubble sorts} can appear in the same document, % though only one can be sorted at a time. % \changes{v1.6}{2020/06/02}{Rewrite whole package to support \string\app{pdflatex}, % \string\app{lualatex}, and \string\app{xelatex} workflows.} % \changes{v1.6.1}{2020/06/17}{Minor changes to conform to CTAN requirements.} % \section{Main Code} % \begin{macrocode} %<*package> % \end{macrocode} % \paragraph*{Required Packages.} % \begin{macrocode} \@ifpackageloaded{eforms}{\let\execjs=y} {\RequirePackage[execJS]{eforms}} \ifxetex\makeXasPDOff\fi % \end{macrocode} % (2020/06/02) We require the \pkg{icon-appr} package. % \begin{macrocode} \RequirePackage{icon-appr} \RequirePackage{multido} \RequirePackage{graphicx} % \end{macrocode} % \section{Some simple controls} % Some buttons to control the starting, stopping and clearing of the image. You can % change the appearance of these buttons by using the optional parameter, see the % \pkg{eforms} documentation. % \begin{macro}{\StartSort}\hskip-\marginparsep\texttt{[\ameta{options}]\darg{\ameta{name}}\darg{\ameta{wd}}\darg{\ameta{ht}}} % Starts the sort for the pictures having the associated \ameta{name}. % \begin{macrocode} \newcommand{\StartSort}[4][] {\pushButton[\CA{Press Me}#1\A{\JS{\sortCustomStartJS;\r startSortAS("#2"); \@ppendStartSortJS}}]{btStartSort}{#3}{#4}% } % \end{macrocode} % \end{macro} % \begin{macro}{\ClearSort}\hskip-\marginparsep\texttt{[\ameta{options}]\darg{\ameta{name}}\darg{\ameta{wd}}\darg{\ameta{ht}}} % Clears the sort for the pictures having the associated \ameta{name}, it does this simply % by making all pictures hidden. % \begin{macrocode} \newcommand{\ClearSort}[4][]% {\pushButton[\CA{Clear}#1\A{\JS{% var f=this.getField("btn#2pic");\r if(f!=null)f.display=display.hidden;\r asOk2Continue = false; \@ppendClearSortJS }}]{btnClearSort}{#3}{#4}% } % \end{macrocode} % \end{macro} % \begin{macro}{\StopSort}\hskip-\marginparsep\texttt{[\ameta{options}]\darg{\ameta{wd}}\darg{\ameta{ht}}} % Starts the sort for the pictures having the associated \ameta{name}. % \begin{macrocode} \newcommand{\StopSort}[3][] {\pushButton[\CA{Stop}#1\A{\JS{% asOk2Continue = false; \@ppendStopSortJS }}]{btnStopSort}{#2}{#3}% } % \end{macrocode} % \begin{macro}{\customStartJS}\hskip-\marginparsep\texttt{\darg{\ameta{script}}} % Inserts \ameta{script} into the beginning of the \cs{StartSort} command. % \begin{macrocode} \newcommand{\customStartJS}[1]{\def\sortCustomStartJS{#1}} \let\sortCustomStartJS\@gobbletwo % \end{macrocode} % \end{macro} % \leavevmode\DescribeMacro\appendStartSortJS\hskip-\marginparsep\texttt{\darg{\ameta{script}}} % Appends \ameta{script} to the \cs{StartSort} control. % \begin{macrocode} \def\appendStartSortJS#1{\def\@rgi{#1}\ifx\@rgi\@empty \let\@ppendStartSortJS\@empty\else \def\@ppendStartSortJS{\r #1}\fi} \let\@ppendStartSortJS\@empty % \end{macrocode} % \leavevmode\DescribeMacro\appendClearSortJS\hskip-\marginparsep\texttt{\darg{\ameta{script}}} % Appends \ameta{script} to the \cs{ClearSort} control. % \begin{macrocode} \def\appendClearSortJS#1{\def\@rgi{#1}\ifx\@rgi\@empty \let\@ppendClearSortJS\@empty\else \def\@ppendClearSortJS{\r #1}\fi} \let\@ppendClearSortJS\@empty % \end{macrocode} % \leavevmode\DescribeMacro\appendStopSortJS\hskip-\marginparsep\texttt{\darg{\ameta{script}}} % Appends \ameta{script} to the \cs{StopSort} control. % \begin{macrocode} \def\appendStopSortJS#1{\def\@rgi{#1}\ifx\@rgi\@empty \let\@ppendStopSortJS\@empty\else \def\@ppendStopSortJS{\r #1}\fi} \let\@ppendStopSortJS\@empty % \end{macrocode} % \end{macro} % \begin{macrocode} % \end{macrocode} %\leavevmode\DescribeMacro\asIconPic\hskip-\marginparsep\texttt % {[\ameta{opts}]\darg{\ameta{fieldname}}\darg{\ameta{wd}}\darg{\ameta{ht}}} % There is allowance for displaying additional button images. The % \begin{macrocode} \newcommand{\asIconPic}[4][]{% \I{\csOf{name}} required \pushButton[\Ff{\FfReadOnly}\BG{}\S{S}#1\TP{1}\F{\FHidden} \PA{.5 1}]{#2}{#3}{#4}} % \end{macrocode} % \section{Embedding the tiles} % The first step is to embed the tiles using the \env{embedding} environment of \pkg{icon-appr}. % \begin{macrocode} % \end{macrocode} % \leavevmode % \DescribeMacro\asEmbedTiles\hskip-\marginparsep\texttt{[\ameta{ext}]\darg{\ameta{name}}\darg{\ameta{n-pics}}\darg{\ameta{path}}} % We take a graphic and explode it into rows and columns, \ameta{n-pics} is the total number % of tiled pictures. We assume the tiles are created row-wise, possible by the \pkg{tile-graphic} package. We assume also a naming convention % for the tiles if \texttt{mypic} is the basename of the picture or graphic, then the tiles are % named \texttt{mypic\_01}, \texttt{mypic\_02}, \texttt{mypic\_03}, \dots. It is assumed a single digit % index has a leading 0. Use the command \DescribeMacro\isPackage % \cs{isPackage} prior to \cs{asEmbedTiles}. % \changes{v1.5}{2020/05/30}{Embed graphics and support for packaged graphics} % \begin{macrocode} \newcount\as@nCnt \newif\if@isPackaged\@isPackagedfalse \def\isPackage{\@isPackagedtrue} \let\asIconObjs\@gobble \newcommand{\asEmbedTiles}[4][]{\begingroup \gdef\asNumSideShowPics{#3}% \csarg\gdef{asGraphicPath#2}{#4}% \def\@Ext{#1}\ifx\@Ext\@empty\def\@Ext{.pdf}\else\def\@Ext{.#1}\fi \@tempcnta\z@ \let\@embedList\@empty % \let\DPSIndxList\@gobble \edef\z{\noexpand\g@addto@macro\noexpand \asIconObjs{,"#2":\asNumSideShowPics}}\z \@whilenum \@tempcnta < \asNumSideShowPics \do{% \as@nCnt\@tempcnta\advance\as@nCnt\@ne \ifnum\as@nCnt<10\relax\edef\x{0\the\as@nCnt}\else \edef\x{\the\as@nCnt}\fi % \edef\z{\noexpand\g@addto@macro\noexpand\DPSIndxList{,"\x"}}\z \ifxetex\if@isPackaged \PackageWarning{acrosort} {There is no support for embedding packaged\MessageBreak PDFs with xelatex. Ignoring the \string\isPackage\MessageBreak command}% \@isPackagedfalse \fi\fi \if@isPackaged \ifpdf \edef\y{\noexpand \embedIcon[name=#2pic\x,% hyopts={page=\x}]{#4_package.pdf}}% \else \edef\y{\noexpand \embedIcon[name=#2pic\x,placement=btn#2pic.\x,% page=\x-1]{#4_package.pdf}}% \fi \else \edef\y{\noexpand \embedIcon[name=#2pic\x,placement=btn#2pic.\x]{#4_\x\@Ext}}% \fi \expandafter\g@addto@macro\expandafter\@embedList\expandafter{\y}% \@tempcnta\as@nCnt }% do \toks@=\expandafter{\@embedList}\the\toks@ \endgroup \global\@isPackagedfalse } % \end{macrocode} % \section{Inserting the tiles to be sorted} The next step is to insert % the tiles into the body of the document, and sort them.\vskip6pt\noindent % \DescribeMacro\insertTiles\hskip-\marginparsep % \texttt{\darg{\ameta{width}}\darg{\ameta{rows}}\darg{\ameta{cols}}} % Command for placing the tiles of a picture. We assume that the pictures are numbered % consecutively across rows. % \begin{quote} % \begin{description} % \item[\ameta{name}] The name of the graphic (a JavaScript identifier) % \item[\ameta{width}] The width of the image, the height is scaled proportionally % \item[\ameta{rows}] The number of rows % \item[\ameta{cols}] The number of columns % \end{description} % \end{quote} % \begin{macrocode} \newcommand\insertTiles[4]{\begingroup \setbox\z@\hbox{% \includegraphics[draft,width=#2]{\@nameuse{asGraphicPath#1}}}% \edef\asGrphWd{\the\wd\z@}% \@tempdima\wd\z@ \divide\@tempdima #4\relax \edef\asTileWd{\the\@tempdima}% \setlength\@tempdima{\ht\z@+\dp\z@}% \setbox\z@\box\voidb@x \edef\asTtlGrphHt{\the\@tempdima}% \@tempdima\asTtlGrphHt\relax \divide\@tempdima #3\relax \edef\asTileHt{\the\@tempdima}% \begin{minipage}{#2}% \offinterlineskip\@tempcnta\z@ \multido{\iR=1+1}{#3}{\hbox{% \multido{\iC=1+1}{#4}{% \global\advance\@tempcnta\@ne \ifnum\@tempcnta<10\relax \edef\x{0\the\@tempcnta}\else \edef\x{\the\@tempcnta}\fi \edef\iconPresets{\noexpand\I{\noexpand\csOf{#1pic\x}}}% \asIconPic[\BC{}\FB{true}\presets{\iconPresets}% \presets{\astile@KVs}]{btn#1pic.\x}{\asTileWd}{\asTileHt}% }% inner multido }}% hbox, outer multido \end{minipage}% \endgroup } % \end{macrocode} % \leavevmode\DescribeMacro\astileKVs\hskip-\marginparsep\texttt{\ameta{KV-pairs}} % A way to pass \pkg{eform} key-values to the optional % argument of the underlying push button. % \begin{macrocode} \def\astileKVs#1{\def\astile@KVs{#1}} \astileKVs{} % \end{macrocode} % % \section{Document JavaScript for \textsf{acrosort}} % Most of the work of this package is done with document JavaScript, and here % it is. % \begin{macro}{\customFinishJS}\hskip-\marginparsep\texttt{\darg{\ameta{script}}} % Inserts \ameta{script} at the end of the bubble sort. % \begin{macrocode} \newcommand{\customFinishJS}[1]{\gdef\sortCustomFinishJS{#1}} \def\sortCustomFinishJS{;} % \end{macrocode} % \end{macro} % \begin{macrocode} \begin{insDLJS}{asSort}{AcroSort: Bubble Sort} // Global Data: var btnbase=""; // btnpic.01, btnpic.02, etc var iconbase=""; // pic01, pic02, etc. var iconObjs={\asIconObjs}; var sortName=""; var randomAS = new Array(); var timeout = 10; var shutdown; var asOk2Continue = false; function initRandomDPS(name) { var nTotalTiles = iconObjs[name]; for (i=1; i<=nTotalTiles; i++) randomAS[i]=i; return nTotalTiles; } % \end{macrocode} % \leavevmode\IndexJS{startSortAS}\hskip-\marginparsep\texttt{(\ameta{name})} is the function % that starts the sorting. % \begin{macrocode} function startSortAS(name) { if (!asOk2Continue) { sortName=name; randomAS = new Array(); var f=this.getField("btn"+name+"pic"); if(f!=null)f.display=display.visible; asOk2Continue = true; mixupAS(); showAS(); sortoutAS(); } } function mixupAS() { var i, rand, temp; var nTotalTiles=initRandomDPS(sortName); var ldps = randomAS.length; for (i=1; i<= nTotalTiles; i++) { var rand = Math.random(); rand *= ldps*ldps; rand = Math.ceil(rand); rand = rand \% ldps; if (rand == 0 ) rand = 1; temp = randomAS[i]; randomAS[i]=randomAS[rand]; randomAS[rand]=temp; } } function showAS() { var I,J; var nTotalTiles = iconObjs[sortName]; btnbase="btn"+sortName+"pic."; iconbase=sortName+"pic"; for ( var i=1; i<=nTotalTiles; i++ ) { I=((i<10)?"0":"")+i; J=((randomAS[i]<10)?"0":"")+randomAS[i]; var oIcon = this.getIcon(iconbase+J); var f = this.getField(btnbase+I); f.buttonSetIcon(oIcon); } } function sortoutAS() { outerLoop(randomAS.length-1); } function outerLoop(i) { if ( asOk2Continue && (i >= 0) ) shutdown = app.setTimeOut("app.clearTimeOut(shutdown); % innerLoop("+i+",1);", timeout); else { asOk2Continue=false; \sortCustomFinishJS } } function innerLoop(i,j) { var I, J; if ( j <= i ) { if (randomAS[j-1] > randomAS[j]) { var temp = randomAS[j-1]; randomAS[j-1] = randomAS[j]; randomAS[j] = temp; J=((randomAS[j-1]<10)?"0":"")+randomAS[j-1]; I=((j-1 < 10)?"0":"")+(j-1); var oIcon = this.getIcon(iconbase+J); var f = this.getField(btnbase+I); f.buttonSetIcon(oIcon); J=((randomAS[j]<10)?"0":"")+randomAS[j]; I=((j < 10)?"0":"")+j; var oIcon = this.getIcon(iconbase+J); var f = this.getField(btnbase+I); f.buttonSetIcon(oIcon); } j++ if ( asOk2Continue ) % shutdown = app.setTimeOut("app.clearTimeOut(shutdown); % innerLoop("+i+","+j+");", timeout); } else { i--; outerLoop(i); } } \end{insDLJS} % % \end{macrocode} % \Finale \endinput