% \iffalse meta-comment
%<*internal>
\iffalse
%</internal>
%<*internal>
\fi
\def\nameofplainTeX{plain}
\ifx\fmtname\nameofplainTeX\else
  \expandafter\begingroup
\fi
%</internal>
%<*install>
\input docstrip.tex
\keepsilent
\askforoverwritefalse
\preamble
\endpreamble
\ifx\fmtname\nameofplainTeX
\generate{
  \file{\jobname.sty}{\from{\jobname.dtx}{copyright,package}}
}
\fi
%</install>
%<install>\endbatchfile
%<*internal>
\ifx\fmtname\nameofplainTeX
  \expandafter\endbatchfile\else
  \expandafter\endgroup\fi
%</internal>
%<*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.      %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%</copyright>
%<package>\NeedsTeXFormat{LaTeX2e}
%<package>\ProvidesPackage{aeb_dad}
%<package> [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}
%</driver>
% \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<stamps.length; i++) {
            var index=stamps[i].subject+page;
            stamps[i].rect=aDADStamp[index][stamps[i].AP][0];
            stamps[i].setProps({rotate:0})
        }
        resetFocus("ddReset"+ddName);
        this.dirty=false;
        return;
    }
    for (var i=0; i<stamps.length; i++) {
    	var aStmpRect=stamps[i].rect;
        var index=stamps[i].subject+page;
%    \end{macrocode}
% Format for Rotated User Space: \texttt{[left,top,right,bottom]}
%    \begin{macrocode}
    	var stmpWidth=aStmpRect[2]-aStmpRect[0];
    	var stmpHeight=aStmpRect[3]-aStmpRect[1];
    	var nHorzCenter=(aStmpRect[2]+aStmpRect[0])/2;
    	var nVertCenter=(aStmpRect[3]+aStmpRect[1])/2;
    	// See if the center of this stamp is in the button rect
    	if ( (nHorzCenter >= 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<stamps.length; i++) {
        if ( stamps[i].subject == ddName ) {
            stamps[i].rect=aDADStamp[ddName+page][stamps[i].AP][0];
            stamps[i].setProps({rotate:0})
            aDADStamp[ddName+page][stamps[i].AP][1]=false;
        }
    }
    aDADCnt[ddName+page]=[0,0];
    for (var i=0; i<this.numFields; i++) {
        var fname=this.getNthFieldName(i);
%    \end{macrocode}
% All fields have the two character sequence \texttt{"@\#"} in it.
% We search for this, if not found, it is an ordinary field.
%    \begin{macrocode}
        var getIndexOf = fname.indexOf("@#");
        if ( (getIndexOf!=-1) %
&& (fname.substring(0,getIndexOf)==ddName) ) {
            var f=this.getField(fname);
            if (f.readonly) {
                f.readonly=false;
                f.strokeColor=color.black;
            }
        }
    }
    if (typeof ddCustomResetAction=="function")
        ddCustomResetAction(page,ddName);
    this.dirty=false;
}
var ddGoodVersion=true;
function ddOpenDocAction() {
    if (app.viewTyper == "Reader" && app.viewerVersion<11) {
        console.show(); app.beep();
        console.println("---------------------------");
        console.println("Any version of Adobe Acrobat, "
            +"or Adobe Reader XI is required!");
        console.println("---------------------------");
        ddGoodVersion=false;
    }
    if (ddGoodVersion) {
        for (var p=0; p<this.numPages; p++) {
            // if there is a game of this page, execute ddPageOpen(p)
            ddPageOpen(p);
        }
    }

}
function ddPageOpen(page) {
%    \end{macrocode}
% We want to execute the stamp code only once, the first time the page
% is opened. If \texttt{ddmPage<pageNum>} is undefined, we set the switch
% \texttt{bInt} to \texttt{true}. We then declare \texttt{ddmPage<pageNum>}.
%    \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<stamps.length; i++) {
            var si=stamps[i];
            if ( si.type=="Stamp") {
%    \end{macrocode}
% We store only annots of type Stamp.
%    \begin{macrocode}
                var index=si.subject+page;
%    \end{macrocode}
% If \texttt{aDADStamp[stamps[i].subject+this.pageNum]}, is undefined,
% we define it.
%    \begin{macrocode}
                if (typeof aDADStamp[index]=="undefined" ) {
                    aDADStamp[index]=new Array();
%    \end{macrocode}
% \texttt{aDADCnt} will keep track of the score. The first entry
% is the number correct, the second entry is the number of tries.
%    \begin{macrocode}
                    aDADCnt[index]=[0,0];
                }
%    \end{macrocode}
% Stamp data is stored by \texttt{<subject><page>}, 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}
%</package>
%    \end{macrocode}
%\Finale
