/******************************************************************************/
//    module: FAbout.cpp   version 1.2b                                       //
//                                                                            //
//    About-dialog with a few lines of text and an animated icon playing      //
//    pinball with the dialogs frame.                                         //
//                                                                            //
//    copyright (c) 2000-2003 by lars haendel                                 //
//    home: http://www.newty.de                                               //
//                                                                            //
//    This program is free software and can be used under the terms of the    //
//    GNU licence. See header-file for further information and disclaimer.    //
//                                                                            //
/******************************************************************************/


#include <vcl.h>
#pragma hdrstop

#include <math>                   // due to:  cos()/sin()
#include <stdio>                  //          sprintf()
#include <process>                //          _beginthread()


#pragma package(smart_init)
#pragma resource "*.dfm"


//----------------------------------------------------------------------------------------------------------------------
#include "FAbout.h"

#define SZ_PURPOSE   "A Gui for the cluster algorithm PNC2"
#define SZ_AUTHOR    "Lars Haendel"
#define SZ_URL       "http:\/\/www.newty.de\/pnc2/index.html"
#define SZ_EMAIL     "mailto:lars.nospam@gmx.de?subject=Contact PNC2"


TFAbout *FAbout;
//----------------------------------------------------------------------------------------------------------------------
// constructor
__fastcall TFAbout::TFAbout(TComponent* Owner, const char* name, const AnsiString szDir) : TForm(Owner)
{
// ToDo: move code to OnShow() ??

   // compose and set dialog's caption
   char text1[256];
   sprintf(text1, "About the program %s", name);
   Caption = AnsiString(text1);

   // ask for the size of an icon - usually 32x32
   cxIcon = GetSystemMetrics(SM_CXICON);
   cyIcon = GetSystemMetrics(SM_CYICON);


   // create and load the two icons
   icon1 = new TPicture;
   icon2 = new TPicture;

   icon1->LoadFromFile(szDir + "smiley1.ico");
   icon2->LoadFromFile(szDir + "smiley2.ico");

   // icon start position
   randomize();
   xIcon = random(Width);             // initialize icon position and ...
   yIcon = random(Height);
   directionPhi = 1;                  // ... moving direction


   // set the icon to be shown in the image, set its size and show it
   Image->Picture  = icon1;


   // create panel
   panel = new TPanel(this);
   panel->Parent = this;
   panel->HandleNeeded();                   // this creates the window
   panel->BorderStyle = bsNone;
   panel->BevelInner  = bvNone;
   panel->BevelOuter  = bvNone;
   panel->FullRepaint = false;



   // set the panel position to be the same as the Image's one
   panel->Left   = xIcon;
   panel->Top    = yIcon;
   panel->Width  = cxIcon;
   panel->Height = cyIcon;


   Image->Parent   = panel;    // make the panel to be the image's parent ...
   Image->Left     = 0;        // ... and position it inside the panel
   Image->Top      = 0;


   // exchange the panel's WindowProc() function
   OldWindowProc = panel->WindowProc;              // remember old one
   panel->WindowProc = NewWindowProc;              // set new one


   Timer->Enabled=true;                            // enable timer


   // wrap handle in the wrapper (needed to pass it by pointer to a thread function
   wrapper.hwnd = Handle;
}


//----------------------------------------------------------------------------------------------------------------------
// initialize purpose and author texts
void __fastcall TFAbout::FormShow(TObject *Sender)
{
   LaPurpose  ->Caption = AnsiString("// ") + SZ_PURPOSE;
   LaWrittenBy->Caption = AnsiString("// Written by ") + SZ_AUTHOR;
}



//----------------------------------------------------------------------------------------------------------------------
// disable timer and restore the panel's old WindowProc() function
void __fastcall TFAbout::OnClose(TObject *Sender, TCloseAction &Action)
{
   panel->WindowProc = OldWindowProc;     // restore
   Timer->Enabled = false;                // disable timer
   Action = caFree;                       // emulates 'wfDeleteOnClose' behaviour
}


//----------------------------------------------------------------------------------------------------------------------
// eliminate the panel's WM_ERASEBKGND message and forward all other
void __fastcall TFAbout::NewWindowProc(TMessage& msg)
{
   if(msg.Msg == WM_ERASEBKGND)
      msg.Result=false;
   else
      OldWindowProc(msg);
}

//----------------------------------------------------------------------------------------------------------------------
// close dialog if user hits escape
void __fastcall TFAbout::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
{
   if(Key==VK_ESCAPE)
      Close();
}


//----------------------------------------------------------------------------------------------------------------------
// evaluate timer event: move the panel with the icon and check for contact with the dialog's frame
void __fastcall TFAbout::OnTimer(TObject *Sender)
{
   // eventually restore display to the standard-icon
   if(nSmile == 0)
      Image->Picture = icon1;
   nSmile--;                  // decrease counter


   // calculate new position
   xIcon +=  2.5*cos(directionPhi);
   yIcon += -2.5*sin(directionPhi);


   // check calculated position against the dialog's border and "reflect" if the icon hits it
   if(xIcon < 0)                                      // left border
   {
      xIcon             = 0;
      directionPhi      = -directionPhi + M_PI;
      nSmile            = 5;
      Image->Picture    = icon2;
   }


   if(yIcon < 0)                                      // top border
   {
      yIcon             = 0;
      directionPhi      = -directionPhi;
      nSmile            = 5;
      Image->Picture    = icon2;
   }

   if(xIcon > ClientWidth-cxIcon)                     // right border
   {
      xIcon             = ClientWidth-cxIcon;
      directionPhi      = -directionPhi + M_PI;
      nSmile            = 5;
      Image->Picture    = icon2;
   }

   if(yIcon > ClientHeight-cyIcon)                    // bottom border
   {
      yIcon             = ClientHeight-cyIcon;
      directionPhi      = -directionPhi;
      nSmile            = 5;
      Image->Picture    = icon2;
   }

   panel->Left = xIcon;   // move panel with the icon inside
   panel->Top  = yIcon;
}


   //-------------------------------------------------------------------------------------------------------------------
   //   functions which start browser and mail client
   //

//----------------------------------------------------------------------------------------------------------------------
// function executes the shell command in an additional thread - see below
void OpenURL(void* _tmp)
{
   TFAbout::THandleWrap* tmp = (TFAbout::THandleWrap*) _tmp;
   ShellExecute(tmp->hwnd, "open", SZ_URL, 0, 0, SW_NORMAL);
}

//----------------------------------------------------------------------------------------------------------------------
// function executes the shell command in an additional thread - see below
void OpenMail(void* _tmp)
{
   TFAbout::THandleWrap* tmp = (TFAbout::THandleWrap*) _tmp;
   ShellExecute(tmp->hwnd, "open", SZ_EMAIL, 0, 0, SW_NORMAL);
}

//----------------------------------------------------------------------------------------------------------------------
// functions open homepage URL in browser or mail client. both call a thread function which executes
// the necessary shell command.  done this way cause some browsers need a long time to open ... ;-)
void __fastcall TFAbout::UrlClick(TObject *Sender)
{
   _beginthread(OpenURL, 4096, (void*) &wrapper);
   Image->Picture = icon2;
}

void __fastcall TFAbout::MailClick(TObject *Sender)
{
   _beginthread(OpenMail, 4096, (void*) &wrapper);
   Image->Picture = icon2;
}