% \iffalse meta-comment %<*internal> \iffalse % %<*internal> \fi \def\nameofplainTeX{plain} \ifx\fmtname\nameofplainTeX\else \expandafter\begingroup \fi % %<*install> \input docstrip.tex \keepsilent \askforoverwritefalse \preamble \endpreamble \ifx\fmtname\nameofplainTeX \generate{ \file{\jobname.sty}{\from{\jobname.dtx}{copyright,package}} } \fi % %\endbatchfile %<*internal> \ifx\fmtname\nameofplainTeX \expandafter\endbatchfile\else \expandafter\endgroup\fi % %<*copyright> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% aebstmpg.sty package, 2012/10/29 %% %% Copyright (C) 2012 D. P. Story %% %% dpstory@uakron.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{aeb_dad} % [2012/11/03 v1.0 Support for a stamp matching game] %<*driver> \documentclass{ltxdoc} %\usepackage{\jobname} %\usepackage[numbered]{hypdoc} %\EnableCrossrefs %\CodelineIndex %\RecordChanges \begin{document} \DocInput{\jobname.dtx} \end{document} % % \fi % %\GetFileInfo{\jobname.sty} % %\title{The \textsf{aeb\_dad} Package} %\author{D. P. Story} %\date{Released \today} % %\maketitle % %\StopEventually{^^A % \PrintChanges % \PrintIndex %} % % \begin{macrocode} %<*package> % \end{macrocode} % \paragraph*{Description.} % The \textsf{aeb\_dad} package consists of {\LaTeX} commands and JavaScript for creating a % \underbar{d}rag \underbar{a}nd \underbar{d}rop ``game'' of matching. The % user drags and drops an icon image and drops it into a target region (a % push button), then clicks on the button. If the placement is correct, the % image centers itself in the target region and the border changes color. % If the user drops the image in the wrong region, the icon is returned to % its initial position. In each case an alert message appears and announces % ``Right'' or ``Wrong''. % % Generally, \textsf{AA} and \textsf{AR} do not support drag and % drop. In version 11 (XI) of \textsf{AR}, you can move a stamp around on a page. % This opens a number of possibilities. \textsf{aeb\_dad} uses a (rubber) % stamp as the icons that can be move around in \textsf{ARXI} (and % \textsf{AAXI}). You cannot attach JS to a stamp, however, that is why the % target of the drop is a push button. The user drops the stamp on a target % and presses the underlying button. The JS associated with the button then % determines whether the stamp that is within its bounding rectangle is the % correct one. % % \paragraph*{Documentation and Code.}\strut\par\medskip\noindent % The \textsf{eforms} package is also required, but it is not listed here. Include % \textsf{eforms} prior to this package. The \textsf{web} package is encourage, but % not required. % \begin{macrocode} \RequirePackage{annot_pro}[2011/11/10] \RequirePackage{xkeyval} \RequirePackage{calc} % \end{macrocode} % \DescribeMacro{\ddDimens} is a macro to set the dimensions of % the stamp icons and the push buttons. % \begin{macrocode} \newcommand{\ddDimens}[1]{\setkeys{ddm}{#1}} % \end{macrocode} % The width of the icon stamp. (Height appropriately scaled) % \begin{macrocode} \define@key{ddm}{iconwidthTo}[]{{% \def\ddm@argi{#1}\ifx\ddm@argi\@empty \global\let\ddm@iconwidthTo\@empty \else \setlength{\dimen@}{#1}% \xdef\ddm@iconwidthTo{\the\dimen@}% \fi }} \define@key{ddm}{iconwidth}[\defaultStampWidth]{{% \setlength{\dimen@}{#1}% \xdef\ddm@iconwidth{\the\dimen@}% }} \define@key{ddm}{iconheight}[\defaultStampHeight]{{% \setlength{\dimen@}{#1}% \xdef\ddm@iconheight{\the\dimen@}% }} % \end{macrocode} % The width of the target button. % \begin{macrocode} \define@key{ddm}{targetwidth}{{% \setlength{\dimen@}{#1}% \xdef\ddm@targetwidth{\the\dimen@}% }} % \end{macrocode} % The height of the target button. % \begin{macrocode} \define@key{ddm}{targetheight}{{% \setlength{\dimen@}{#1}% \xdef\ddm@targetheight{\the\dimen@}% }} % \end{macrocode} % We set some reasonable defaults for \cs{ddDimens}. % \begin{macrocode} \ddDimens{iconwidth,iconheight,iconwidthTo,% targetwidth=1.25in,targetheight=1.25in} % \end{macrocode} % \DescribeMacro{\ddGameIcon} is a convenience command for placing % the icon stamps. The one required argument is the name associated % with the stamp. % \begin{macrocode} \newcommand{\ddGameIcon}[1]{% \ifx\ddm@iconwidthTo\@empty \def\ddGameIconArgs{type=stamp,name=\##1,% width=\ddm@iconwidth,% height=\ddm@iconheight}% \else \def\ddGameIconArgs{type=stamp,name=\##1,% width=\ddm@iconwidth,% height=\ddm@iconheight, widthTo=\ddm@iconwidthTo}% \fi % \end{macrocode} % Finally we use \cs{annotpro} to create the stamp. % \begin{macrocode} \expandafter\annotpro\expandafter[\ddGameIconArgs]{}% } % \end{macrocode} % \DescribeMacro{\ddBtnAppr} is the preset button appearance for the % target buttons. % \begin{macrocode} \newcommand{\ddBtnAppr}{\S{S}\BG{} \AA{\AAMouseEnter{% \JS{btnMouseUpAction(event,this.pageNum,"\thisDDNAME");}}}% } % \end{macrocode} % \DescribeMacro{\ddTargetOfIcon} is a convenience command for placing % a push button. The two are arguments, the first is the name of the stamp % associated with this target, the second is the caption that is to go beneath % the button. % \begin{macrocode} \newcommand{\ddTargetOfIcon}[2]{% \parbox[t]{\ddm@targetwidth} {\kern0pt\pushButton[\presets{\ddBtnAppr} ]{\thisDDNAME @\##1}{\ddm@targetwidth}{\ddm@targetheight}% \ddTargetCaption{#2}}% } \newcommand{\ddTargetFmt}[1]{\def\ddm@targetfmt{#1}} \ddTargetFmt{} \newcommand{\ddTargetCaption}[1]{\\[3pt]% \parbox[t]{\linewidth}{\centering\ddm@targetfmt#1}} % \end{macrocode} % \paragraph*{Page and Document JavaScript}\strut\par\medskip\noindent % As of this writing, only one drag and drop stamp game per page. The % \DescribeMacro{\initDDGame}\cs{initDDGame} macro should appear on that page. % \begin{macrocode} \newcommand{\thisDDName}[1]{% \setAnnotOptions{subject={#1}}% \def\thisDDNAME{#1}% } \newcommand{\initDDGame}[1]{\thisDDName{#1}% \@ifundefined{ddEmitOnPage\thepage}{% \expandafter\let\csname ddEmitOnPage\thepage\endcsname\@empty \thisPageAction{\JS{ddPageOpen(this.pageNum);}}{}% }{}% } % \end{macrocode} % \DescribeMacro{\ddReset} is the reset button for the drag and drop matching game. % % It is recommended that the reset button is between the icons and the % target buttons. The game executes a \texttt{Field.setFocus()} method to take the focus % off of the stamps when they are dropped. The focus goes on the reset button. % if the reset button is out of the user's viewing, AA or AR will scroll the page % to place the reset button in the (middle of the ) viewing area % \begin{macrocode} \newcommand{\ddReset}[1][]{% \def\dd@arg{#1}\ifx\dd@arg\@empty\else \thisDDName{#1}\fi \mbox{\makebox[0pt][l]{% \pushButton[\W0\BC{}\BG{}\S{S}]{ddHReset\thisDDNAME}{0bp}{0bp}}% \pushButton[\CA{Reset}\A{\JS{% resetDDM(this.pageNum,"\thisDDNAME");}} \AA{\AAOnFocus{\JS{% this.getField("ddHReset\thisDDNAME").setFocus(); }}}% ]{ddReset\thisDDNAME}{}{11bp}}% } % \end{macrocode} % Open action, to warn user that XI is required for reader. % \begin{macrocode} \OpenAction{\JS{ddOpenDocAction();}} % \end{macrocode} % \paragraph*{Document JavaScript.} % The JavaScript function called by the target push buttons. % \begin{macrocode} \newcommand{\ddRightMsg}{"Right!"} \newcommand{\ddWrongMsg}{"Wrong!"} \newcommand{\ddDragOnlyOne}{"Drag one icon at a time"} \begin{insDLJS}{dadjs}{JS for AcroTeX Stamp Game} var aDADStamp=new Array(); var aDADCnt=new Array(); function btnMouseUpAction(event,page,ddName) { var stamps; var aBtnRect=event.target.rect; var cBtnName=event.target.name; var l = cBtnName.indexOf("@#"); cBtnName = cBtnName.substring(1+l); // convert to rotated user coordinates var mxToDefault=(new Matrix2D()).fromRotated(this,page); var mxToRotated=mxToDefault.invert(); var aBtnRectRot=mxToRotated.transform(aBtnRect); % \end{macrocode} % Format for Default User Space: \texttt{[left,bottom,right,top]} % \begin{macrocode} var btnWidth=aBtnRect[2]-aBtnRect[0]; var btnHeight=aBtnRect[3]-aBtnRect[1]; % \end{macrocode} % Originally, we gathered all annots on this page, %\begin{verbatim} % stamps=this.getAnnots(page); %\end{verbatim} % Now we gather the selected annots (throughout the entire document) % \begin{macrocode} stamps=this.selectedAnnots; if (typeof stamps == "undefined") return; if (stamps.length>1) { app.alert({cMsg: \ddDragOnlyOne, nIcon: 3, cTitle: "AcroTeX Drag and Drop"}); for (var i=0; i= aBtnRectRot[0] ) % && (nHorzCenter<=aBtnRectRot[2]) ) { if ( (nVertCenter>=aBtnRectRot[3]) % && (nVertCenter<=aBtnRectRot[1]) ) { // center of stamp is inside rectangle // Now see if it is the correct one. if (( (cBtnName==stamps[i].AP) % && (stamps[i].subject==ddName)) % && (!aDADStamp[index][stamps[i].AP][1]) ) { // center stamp on button face % \end{macrocode} % Field: \texttt{[left,bottom,right,top]}\\ % Annot: \texttt{[left,top,right,bottom]}\\ % We get the original rectangle, and use it to calculate the width and height. % \begin{macrocode} var aStmpRect=aDADStamp[index][stamps[i].AP][0]; var stmpWidth=aStmpRect[2]-aStmpRect[0]; var stmpHeight=aStmpRect[3]-aStmpRect[1]; aDADStamp[index][stamps[i].AP][1]=true; var deltaX=(btnWidth-stmpWidth)/2; var deltaY=(btnHeight-stmpHeight)/2; % \end{macrocode} % We calculate the dimensions of the centered icon. If the user rescaled the icon % it will be locked in at its original scale. % \begin{macrocode} aCenterStamp=[ aBtnRectRot[0]+deltaX, aBtnRectRot[3]-deltaY, aBtnRectRot[0]+deltaX+stmpWidth, aBtnRectRot[3]-deltaY-stmpHeight]; ddCorrectAction(event,ddName); event.target.strokeColor=color.green; % \end{macrocode} % Correct stamp in the correct target field. We want to center the stamp, make sure % the user did not rotate it, or resize it. % \begin{macrocode} stamps[i].setProps({rotate:0}); stamps[i].rect=aCenterStamp; event.target.readonly=true; resetFocus("ddReset"+ddName); break; } else { ddWrongAction(event,ddName); stamps[i].setProps({rotate:0}) stamps[i].rect=aDADStamp[index][stamps[i].AP][0]; resetFocus("ddReset"+ddName); break; } } else { // too high or two low. if(!aDADStamp[index][stamps[i].AP][1]) stamps[i].rect=aDADStamp[index][stamps[i].AP][0]; stamps[i].setProps({rotate:0}) resetFocus("ddReset"+ddName); } } else { // outside left or right of button if(!aDADStamp[index][stamps[i].AP][1]) stamps[i].rect=aDADStamp[index][stamps[i].AP][0]; stamps[i].setProps({rotate:0}) resetFocus("ddReset"+ddName); } } this.dirty=false; } function resetDDM(page,ddName) { var stamps=this.getAnnots(page); for (var i=0; i} is undefined, we set the switch % \texttt{bInt} to \texttt{true}. We then declare \texttt{ddmPage}. % \begin{macrocode} eval("var bInit=(typeof ddmPage"+page+"=='undefined')"); eval("var ddmPage"+page+"=true;"); if (bInit) { this.syncAnnotScan(); % \end{macrocode} % We get the array of all annots on this page. % \begin{macrocode} var stamps=this.getAnnots(page); if (stamps==null) return; for (var i=0; i}, a particular stamp % is referenced by its \texttt{AP} name. We save the original rectangle % and a boolean \texttt{false}. When the stamp is placed correctly, we % change this to \texttt{true}. % \begin{macrocode} aDADStamp[index][si.AP]=[si.rect, false]; } } } } function resetFocus(fname) { this.getField(fname).setFocus(); } function ddCorrectAction(event,ddName) { if (typeof ddCustomCorrectAction == "function") % \end{macrocode} % Customization: If \texttt{ddCustomCorrectAction()} is defined, we use it. % \begin{macrocode} ddCustomCorrectAction(event,ddName); else app.alert(\ddRightMsg); } function ddWrongAction(event,ddName) { if (typeof ddCustomWrongAction == "function") % \end{macrocode} % Customization: If \texttt{ddCustomWrongAction()} is defined, we use it. % \begin{macrocode} ddCustomWrongAction(event,ddName); else app.alert(\ddWrongMsg); } \end{insDLJS} % \end{macrocode} % \begin{macrocode} % % \end{macrocode} %\Finale