/*----------------------------------------------------------------------------*/
/*                                                                            */
/* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved.             */
/* Copyright (c) 2005-2014 Rexx Language Association. All rights reserved.    */
/*                                                                            */
/* This program and the accompanying materials are made available under       */
/* the terms of the Common Public License v1.0 which accompanies this         */
/* distribution. A copy is also available at the following address:           */
/* https://www.oorexx.org/license.html                                        */
/*                                                                            */
/* Redistribution and use in source and binary forms, with or                 */
/* without modification, are permitted provided that the following            */
/* conditions are met:                                                        */
/*                                                                            */
/* Redistributions of source code must retain the above copyright             */
/* notice, this list of conditions and the following disclaimer.              */
/* Redistributions in binary form must reproduce the above copyright          */
/* notice, this list of conditions and the following disclaimer in            */
/* the documentation and/or other materials provided with the distribution.   */
/*                                                                            */
/* Neither the name of Rexx Language Association nor the names                */
/* of its contributors may be used to endorse or promote products             */
/* derived from this software without specific prior written permission.      */
/*                                                                            */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS        */
/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT          */
/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS          */
/* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT   */
/* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,      */
/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED   */
/* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,        */
/* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY     */
/* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING    */
/* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS         */
/* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.               */
/*                                                                            */
/*----------------------------------------------------------------------------*/

/**
 *  oowalk2.rex  Animation demonstration (using a compiled binary resource
 *  for the dialog template.  A DLL file.)
 *
 *  The only real difference between this sample and the oowalker.rex sample is
 *  the way the bitmaps for the animation are loaded.  Look at the initDialog()
 *  method of the .WalkerDialog to see this difference.
 *
 *  An animated button is used to simulate a man walking across the dialog.  The
 *  user can adjust the pace of the waling by setting the amount the man is
 *  moved each time the button is redrawn and the delay between redrawing the
 *  button.  The button is drawn using a sequence of bitmaps that show the man
 *  with different leg and arm positions.  The user can also set how the man
 *  'walking' off the edge of the dialog is handled, smoothly or bouncy, by
 *  using the "smooth corner wrap" check box.
 *
 *  A 'got cha' point (!!!) is periodically drawn and if the man is close enough
 *  to this 'danger,' the man is 'gotten' and the animation is stopped.  Each
 *  time the button is drawn, the !!! is over-drawn, so the !!! is only seen
 *  as a flicker.
 *
 *  Normally the dialog ends when the walker is gotten.  However there is a
 *  check box that allows the user to cancel this behavior and then restart the
 *  animation.
 */

 srcDir = locate()
 .application~setDefaults('O', srcDir'rc\walker.h', .false)

 dlg = .WalkerDialog~new(srcDir'res\oowalk2.dll', IDD_WALKER)

 if dlg~initCode \= 0 then do
   mgr~goBack
   return 99
 end
 dlg~execute("SHOWTOP")

 return

/*---------------------------- requires -----------------------------*/

::requires "ooDialog.cls"
::requires "samplesSetup.rex"

/*---------------------------- walker dialog ------------------------*/

::class 'WalkerDialog' subclass ResDialog

::method initDialog
   expose bitmaps spriteButton quitCheckBox restartButton okButton

   -- Make button IDC_DRAW_BUTTON a bitmap button.  Bitmap buttons are owner-
   -- drawn and ooDialog will manage the 'drawing' of the button by painting a
   -- series of bitmaps on the button, using the AnimatedButton class.
   self~installBitmapButton(IDC_DRAW_BUTTON, '', 0);

   -- The bitmaps are loaded from the resource DLL by specifying their resouce
   -- IDs in the DLL file, res\oowalk2.dll.
   --
   -- We use symbolic IDs for the  bitmaps, and we assigned the IDs in order.
   -- In the new() method, the 2nd arg is the first bitmap ID and the 3rd is the
   -- last bitmap ID and they are assumed to be in order.  The AnimatedButton
   -- class was never updated to accept symbolic IDs, so we need to convert the
   -- IDs to numeric IDs
   bmpFirst = .constDir[ID_BMP_FIG1]
   bmpLast  = .constDir[ID_BMP_FIG8]
   spriteButton = .WalkButton~new(IDC_DRAW_BUTTON, bmpFirst, bmpLast, 10, 2, 70, 120, 60, 10, 10, self)

   -- Use 'bouncy' operation when hitting edges.
   spriteButton~setSmooth(.false)

   -- Size of the step through the bitmap IDs.
   spriteButton~setstep(1)

   -- Get things set up.
   self~connectButtonEvent(IDC_PB_RESTART, "CLICKED", onRestart)

   quitCheckBox  = self~newCheckBox(IDC_CB_GOTCHA)
   restartButton = self~newPushButton(IDC_PB_RESTART)
   okButton      = self~newPushButton(IDOK)

   quitCheckBox~check
   spriteButton~fillData(data.)
   spriteButton~suspendGotCha(.false)
   self~doValueStemSet(data.)
   ret = Play(srcDir"tada.wav", n)  -- TODO not playing in Win7

   -- Animate the button.
   spriteButton~run

::method doValueStemGet unguarded
  use strict arg data.
  data.IDC_EDIT_MOVEX = self~newEdit(IDC_EDIT_MOVEX)~getText
  data.IDC_EDIT_MOVEY = self~newEdit(IDC_EDIT_MOVEY)~getText
  data.IDC_EDIT_DELAY = self~newEdit(IDC_EDIT_DELAY)~getText
  if self~newCheckBox(IDC_CB_SMOOTH)~checked then data.IDC_CB_SMOOTH = 1
  else data.IDC_CB_SMOOTH = 0

::method doValueStemSet unguarded
  use strict arg data.
  self~newEdit(IDC_EDIT_MOVEX)~setText(data.IDC_EDIT_MOVEX)
  self~newEdit(IDC_EDIT_MOVEY)~setText(data.IDC_EDIT_MOVEY)
  self~newEdit(IDC_EDIT_DELAY)~setText(data.IDC_EDIT_DELAY)
  if data.IDC_CB_SMOOTH == 1 then self~newCheckBox(IDC_CB_SMOOTH)~check
  else self~newCheckBox(IDC_CB_SMOOTH)~uncheck

::method onGotCha
   expose okButton
   use strict arg animatedButton, x, y
   okButton~disable
   self~writetoButton(IDC_DRAW_BUTTON, x, y, "Got-cha", "Arial", 28, "BOLD")
   ret = play('gotcha.wav')
   animatedButton~stop
   call msSleep 1000

::method maybeQuit
   expose quitCheckBox restartButton okButton
   if quitCheckBox~checked then return self~ok

   restartButton~enable
   okButton~enable

::method onRestart
   expose spriteButton restartButton
   restartButton~disable
   spriteButton~stopped = .false

   -- Suspend the 'GotCha' before we start the animated button.  Otherwise the
   -- walker will be 'gotten' as soon as he starts.
   spriteButton~suspendGotCha(.true)
   spriteButton~run

   -- Give the walker time to 'walk' out of the danger zone before reactivating
   -- the 'GotCha.'
   delay = self~newEdit(IDC_EDIT_DELAY)~getText
   j = msSleep(2 * delay)
   spriteButton~suspendGotCha(.false)

::method ok unguarded
   self~stopAnimation
   return self~ok:super

::method cancel unguarded
   self~stopAnimation
   return self~cancel:super

::method stopAnimation private
   expose bitmaps spriteButton
   spriteButton~stop

   -- Wait until the animation sequence is finished.
   do while spriteButton~isRunning
     j = msSleep(30)
   end


/*------------------------------ animated button --------------------*/

::class 'WalkButton' subclass AnimatedButton

::method run unguarded
   expose xDanger yDanger running
   xDanger = 300; yDanger = 70; running = .true

   reply 0

   do until self~stopped | self~parentStopped
      self~doAnimatedSequence
   end

   -- Have the walker do one more sequence, gives the appearance of walking 'in
   -- place.'
   self~doAnimatedSequence

   -- We are no longer running, tell the parent dialog to maybe quit.
   running = .false
   self~parentDlg~maybeQuit

::method doAnimatedSequence private unguarded
   expose xDanger yDanger

   self~parentDlg~doValueStemGet(data.)
   do k over data.
      if \ data.k~datatype('N') then data.k = 0
   end
   self~moveseq
   self~setmove(data.IDC_EDIT_MOVEX, data.IDC_EDIT_MOVEY)
   self~setdelay(data.IDC_EDIT_DELAY)
   self~setsmooth(data.IDC_CB_SMOOTH)
   if \ self~stopped then
      self~parentDlg~writetoButton(IDC_DRAW_BUTTON,xDanger,yDanger,"!!!","Arial",20,"BOLD")

::method isRunning unguarded
   expose running
   return running

::method suspendGotCha unguarded
   expose gotCha
   use strict arg suspend
   if suspend then gotCha = .false
   else gotCha = .true

::method hitright
   ret = play('ding.wav', 'YES')
   return 1

::method hitleft
   ret = play('ding.wav', 'YESY')
   return 1

::method hitbottom
   self~getsprite(s.)
   ret = play('chord.wav', 'YES')
   s.movey = -s.movey
   self~setsprite(s.)
   self~fillData(data.)
   self~parentDlg~doValueStemSet(data.)
   return 0

::method hittop
   expose sprite.
   self~getsprite(s.)
   ret = play('chimes.wav', 'YES')
   s.movey = -s.movey
   self~setsprite(s.)
   self~fillData(data.)
   self~parentDlg~doValueStemSet(data.)
   return 0

::method fillData
   expose quitCheckBox
   use arg data.
   if \ quitCheckBox~isA(.CheckBox) then quitCheckBox = self~parentDlg~newCheckBox(IDC_CB_GOTCHA)
   self~getSprite(msprite.)
   data.IDC_EDIT_MOVEX = msprite.movex
   data.IDC_EDIT_MOVEY = msprite.movey
   data.IDC_EDIT_DELAY = msprite.delay
   data.IDC_CB_SMOOTH = msprite.smooth

   if quitCheckBox~checked then data.IDC_CB_GOTCHA = 1
   else data.IDC_CB_GOTCHA = 0

::method movepos
   use arg px, py
   if \ self~stopped then do
      self~movepos:super(px,py)
      self~checkDanger
   end

::method checkDanger
   expose xDanger yDanger gotCha
   self~getpos(cur.)
   if abs(cur.x+10-xDanger) <= 10 & abs(cur.y+55-yDanger) <= 30 then do
      if gotCha then self~parentDlg~onGotCha(self, xDanger-50, yDanger)
   end
