HarmFade Component, by Harm

Copyright © 1998 Technoid Brain Trust
All Rights Reserved

harmans@uswest.net

Version 2.3 - 1/99

Added three new Events: OnMouseEnter, OnMouseLeave, and OnClick. Added two new methods:   UnBlend and UnDissolve.  These excellent suggestions came from Douglas@rexburg.com.  This makes HarmFade a little more useful - it can be used as a quasi-button.  The other change is this document, an attempted improvement over *.txt.  I'm assuming that anyone who downloads this component also has some sort of browser.

Usage Notes - Miscellaneous info
Description - A description of this component and its limitations
System Requirements - What you need to use this component successfully
License Agreement - What's required for you to use this component
Credits - People who have helped improve this component
Installation - How to install this component
Properties - a description of the component properties
Methods - a description of the component methods
Events - a description of the component events
Examples - code snippets and suggestions to get you going

Usage Notes
For D3 users, your projects may need to have jpeg added to the uses clause in order for them to work correctly with HarmFade. D4 seems to include it automatically.

If you have a GIFImage component installed, such as the excellent freeware version by Anders Melander, you can use gif with harmfade also. Be aware that transparency may cause odd behavior with gifs, since they are not specifically addressed within Harmfade. Gif support is not a native Delphi TPicture format, so I did not include code to deal with that.

Description
HarmFade is a Delphi Component that will transition between two TPictures. It's a descendant of TGraphicControl.  It currently has two transitions: Blend and Dissolve.  Blend is a gradual change of the pixels from the first TPicture to the second TPicture.  It's basically a series of merge operations on the two images, changing the percentage from 100% of the first picture to 100% of the second picture gradually.  Dissolve is a pixel swap operation, so that individual pixels are changed from the first picture to the second picture.  It can be used in about boxes for interesting effects, or as a quasi-button.  See the Examples section for details on how to use HarmFade effectively.

System Requirements
HarmFade will only work with Delphi 3 or higher.  It uses the TBitmap.Scanline property introduced in D3, and will not compile in D1 or D2.  It also uses 24bit bitmaps.  It will look OK on 16bit (High) color and above, but looks like crap on 16 or 256 color monitors.  I developed this for my own purposes, and that's how my system is set up.  Sorry about that, but I'm not out to make any money on this, so what you see is what you get.  HarmFade is fairly fast, and should be fine on any Pentium processor, but may be a bit on the slow side on anything less.

License Agreement
This code is freeware. As such, you get what you pay for. No warranties, express or implied, are provided.  The author is not responsible for any problems caused by this component.  Use it at your own risk.  The author provides no support whatsoever, and is not obligated to any person or corporation for anything related to this software.  The author reserves all rights concerning this code.  You are free to use it as you see fit, but if you make modifications or improvements that may benefit the Delphi programming community, I would appreciate hearing from you.  This code cannot be sold for any purposes, or included in a commercial collection, without the express written consent of the author.  By installing these files on your computer, you agree to all above conditions. 

Credits
Many improvements have been made to the original version of this component.   I would like to thank those who have helped make this better, I am always interested in learning how to improve the code/usability.
Sebastion LEON - Provided the assembler code to speed things up dramatically.  A major improvement.  Thanks, Seb.
Cristian Brolin, Dean Crawford, and Douglas ? @Rexburg.com for great suggestions on improvements.
Delphi programmers who have shared their code with the world so we can all learn from it.
Team B and others who have taken the time to give advice and patient explanations on the Borland newsgroups.

Installation

  1. Unzip the files

  2. Copy HarmFade.pas and HarmFade.dcr to the component folder of your choice.

  3. From D3 or D4, select the Component menu item, then Install (component).   Browse to the foler where you copied the files.  Select HarmFade.pas and click OK until it's installed.

By default, HarmFade will be placed on the Samples tab of the Component palette.  To change this, edit the source code and find the register procedure.   Change the 'Samples' to whatever tab you wish, then re-install the component.   Or, use the Configure Palette menu option to move it to the tab you want.

Properties

Property Type
AutoReverse Boolean
BlendRate Integer
ColorFrom, ColorTo TColor
DisolvRate Integer
Finish Boolean
Height Integer
Hint String
Left Integer
Name String
ParentShowHint Boolean
PicFrom, PicTo TPicture
PopupMenu TMenu
ProcessMsgs Boolean
ShowHint Boolean
StretchToFit Boolean
SwapDelay Integer
SwapOnReverse Boolean
Tag Integer
Top Integer
Visible Boolean
Width Integer

AutoReverse - When this is set to true, the blend or dissolve will reverse itself and do an UnBlend or UnDissolve, depending on the SwapOnReverse setting.  The delay before reversal is set with the SwapDelay property.

BlendRate - a value from 1 - 255.   This determines the speed of the blend transition.  Low values are faster.   The smoothest blend rate is 32, but it's pretty fast for smaller images.  The speed of blend is dependent on the Image size.  It takes some experimentation with this value to determine the optimum.

ColorFrom, ColorTo - If a PicFrom or PicTo is not assigned, these colors are used in their stead.  You could blend from solid black color to a Picture by setting PicFrom to nil and setting ColorFrom to clBlack.  If a PicFrom or PicTo is assigned, these settings are ignored.

DisolvRate - a value from 1 - (the HarmFade W x H).  This is similar to the BlendRate, lower numbers are faster.   The speed of dissolve is also dependent on the image size, and will take some experimentation to get set the way you want.

Finish - This property is not published, but is available in your application at run-time.  Setting this property to TRUE will force immediate completion of the transition.  You must set ProcessMsgs to true for this to work properly.

Height, Hint, Left, Name, ParentShowHint - These are normal Delphi VCL properties, common to all Controls.  See delphi help for a description of these.

PicFrom, PicTo - These are the images that harmfade blends or dissolves.  All of the normal TPicture formats are supported: bmp, jpg, wmf, emf, and ico.  They can be assigned at design time via the object inspector, or loaded or assigned at runtime with the normal TPicture methods.   See Examples for more information.

PopupMenu - Normal Delphi PopupMenu, see Delphi help for information on usage.

ProcessMsgs - When set to true, this will allow the blend or dissolve transition to be 'interrupted'.  Normally, HarmFade uses tight loops for drawing and won't allow other processing to take place during the transition.  This must be set to true for the Finish property to take effect.

ShowHint - Normal Delphi ShowHint property, see Delphi help for information on usage.

StretchToFit - When set to true, this will stretchdraw the images to fit into the current HarmFade dimensions.   When set to false, HarmFade will resize itself to fit the PicFrom image, unless:   if PicFrom is not assigned, HarmFade will resize itself to the PicTo dimensions.   If neither is assigned, this property is ignored.

SwapDelay - the amount of time between transition and un-transition, in seconds.  This property is ignored if AutoReverse is false.

SwapOnReverse - changes the transition when doing an UnBlend or UnDissolve.  Ignored if AutoReverse is false.   If true, this will UnDissolve after a Blend, or UnBlend after a Dissolve.

Tag, Top, Visible, Width - These are normal Delphi VCL properties, common to all Controls.  See delphi help for a description of these.

Methods

Method Description
Blend This starts the transition using the Blend effect.  It blends from either PicFrom or ColorFrom to PicTo or ColorTo, depending on propery settings.
Dissolve This starts the transition using the Dissolve effect.  It dissolves from either PicFrom or ColorFrom to PicTo or ColorTo, depending on property settings.
Reset Recalculate sizes, re-draw starting picture (or color).
UnBlend This starts the transition using the Blend effect, but goes in reverse order.  It blends from either PicTo or ColorTo to PicFrom or ColorFrom, depending on property settings.
UnDissolve This starts the transition using the Dissolve effect, but goes in reverse order.  It dissolves from either PicTo or ColorTo to PicFrom or ColorFrom, depending on property settings.


Events

Event Description
OnBegin Fires when transition starts, by either a Blend or Disslove method. 
OnClick Fires when user clicks on HarmFade.  Use like a button click.
OnEnd Fires when transition is complete.
OnMouseEnter Fires when mouse enters HarmFade.
OnMouseLeave Fires when mouse leaves HarmFade.
OnReset Fires when a Reset is done.


Examples
When a THarmFade is dropped on a form (or panel, etc), it will just be a small black box.  It will function without loading any pictures, but is much more effective if PicFrom and/or PicTo is assigned.  Just double-click one of those properties in the Object Inspector to load an image, much like a TImage.  To start the transition, you must use the Blend or Disslove method in your application code:

procedure TForm1.Button1Click(Sender: TObject);
begin
  HarmFade1.Dissolve;
{or}
  HarmFade1.Blend;
end;

If neither the From or To Picture has been assigned, it will transition from a 'ColorFrom' square to a 'ColorTo' square.

After completing the transition, the PicTo (or ColorTo) will remain visible unless
AutoReverse is True, or until either:
1) the effect is started again with .Dissolve or .Blend, or
2) the THarmFade.Reset method is used. This will reset the pictures back to their 'original' state, prior to transition. Changing any of the following properties will also cause the Reset method to be called:
PicFrom, PicTo, ColorFrom, ColorTo, or StretchToFit.

If only one of PicFrom or PicTo is assigned, the transition will use a solid color for the other picture. For example, if PicFrom is
assigned, and PicTo is not, then the ColorTo color will be used instead of PicTo.

If PicFrom or PicTo is a MetaFile or Icon, they support transparency. The background color will be the ColorFrom or ColorTo, respectively.

StretchToFit by default is True. When a picture is assigned, it will StretchDraw it to fit into the current size of HarmFade. If  StretchToFit is False, then the HarmFade is sized to match the PicFrom picture (if assigned) and the PicTo is stretched to match that size. If PicFrom is empty, the HarmFade will be sized based on PicTo. In  order for the fading effect to work, the From and To pictures must be made the same size. I didn't want to force people to size the pictures prior to using this control, so I made up these rules. Again, some experimentation with the pictures and this setting will give you a better feel for how it all works.

ProcessMessages is FALSE by default. The HarmFade uses tight loops for doing the animation, which means your application is locked until it's complete . You can't use buttons, scrollbars, etc in your application until the .Blend or .Dissolve method has completed.  Setting the ProcessMessages property to TRUE allows the animation to be interrupted. It allows the tight loop to be paused for handling other tasks. The animation stops while messages are processed, then continues when it can.

While this all may sound complicated, it's really quite easy to use HarmFade: Drop a THarmFade on a form. Double Click the PicFrom property, and use the Dialog to select a graphic supported by tpicture. Double Click the PicTo property and select a different picture.  (Or leave one of these properties unassigned). Add a TButton to your form, and add the following line to the OnClick:

HarmFade1.Dissolve;

Run the program, then click the button. Watch the dissolve, and adjust the DisolvRate property as desired for maximum effect. To unassign one of the bitmap properties, double click the property and use the Clear button in the dialog. To achieve the same effect in code, use this:

HarmFade1.PicTo := nil;

You can use HarmFade as a crude button, but with interesting effects.   Use your favorite Paint program to design a picture that looks like a button, with very dark colors, or just solid black with gray text (for the 'caption').  Save it, then flood fill the text with a bright color (like red or lime) and save it as a different filename.  Use these as the PicFrom and PicTo, respectively.  Then, in your application, add the following code:

procedure TForm1.HarmFade1MouseEnter(Sender: TObject);
begin
  HarmFade1.Blend;
end;

procedure TForm1.HarmFade1MouseLeave(Sender: TObject);
begin
  HarmFade1.UnBlend;
end;

procedure TForm1.HarmFade1Click(Sender: TObject);
begin
  ShowMessage('You clicked on HarmFade');
end;

When the mouse moves over the HarmFade, it will start the blend transition.  When the mouse leaves the HarmFade, it will UnBlend back to the original image.

You may want to have this Transition effect take place whenever a Form is first shown. This can be achieved by placing the .Dissolve or .Blend method in the form's OnShow event. However, it seems that the transition starts up before the form is completely painted. Thanks to Anders Melander and Joachim Meyer for advice on how to surmount this problem:

*** Add a user message constant (MY_MSG)
*** Add a procedure to handle message (MY_MSG)
*** In Form's OnShow event, Post the new message
*** In the new message handler, do the animation

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, HarmFade;

const
MY_MSG = WM_USER + 1; {<=== Add this}

type
  TForm1 = class(TForm)
  Label1: TLabel;
  HarmFade1 : THarmFade;
  procedure FormShow(Sender: TObject); {<== Add code to OnShow}
....
private
  procedure WeArePainted(var Msg : TMessage); message MY_MSG;
.... {== Add the above procedure ==}

implementation

procedure TForm1.FormShow(Sender: TObject);
begin
  PostMessage(Handle, MY_MSG, 0, 0); {<== Post our new message}
end;

{== The following procedure now gets control once form is painted}
procedure TForm1.WeArePainted(var Msg : TMessage);
begin
  Application.ProcessMessages;
  HarmFade1.Dissolve;
end;

How to make a Splash Screen with a THarmFade component

Here's an example of using a splash screen, with a THarmFade transition method thrown in:

First, design your splash screen form. I modify the form's border property to bsNone to get rid of the title bar. I also make the form's ClientWidth and ClientHeight match the HarmFade1.Width and Height. I would then change the Position to poScreenCenter to make sure it centers in the screen at run-time. Of course, this is all arbitrary.
Assuming you gave the form a name of fSplash....

In the project source code (from the menu, select Project, View Source), make the following modifications:

***Add Windows to the uses clause.
***Add a variable before the begin statement, for your splash form.
***Create your form and show it before creating the other form(s).
***Add the Harmfade.Blend prior to creating other forms.
Here's an example:

program Project1;

uses
  Windows, Forms, <== Add 'Windows' for Sleep()
  Unit1 in 'Unit1.pas' {Form1},
  Splash in 'Splash.pas' {fSplash};

{$R *.RES}

var
Splasher : TfSplash; <== Add var for splash form

begin
  try
    Splasher := TfSplash.Create(Application); <== Create form
    Splasher.FormStyle := fsStayOnTop; <== Stay on Top
    Splasher.Show; <== Show form
    Sleep(1000); <== Delay 1 second
    Splasher.HarmFade1.Dissolve; <== Do dissolve
    Sleep(5000); <== Delay 5 secs
    Application.Initialize;
    Application.CreateForm(TForm1, Form1);
    //Application.CreateForm(TfSplash, fSplash); <==Remove
    Splasher.Close; <== Close splash
  finally
    Splasher.Free; <== Free resources
  end;
  Application.Run;
end.

See the accompanying Demo for more coding examples.

** To make a Harmfade blend from it's underlying form/controls:

Similar to the splash example. Place a Harmfade on your form and set the Visible property to FALSE. Set the PicTo picture to whatever.
* Note - if underlying controls are windowed controls (memo, button, etc) there is a bit of flicker when harmfade effect starts.
The following example uses a couple of buttons to start and stop the effect:

procedure TForm1.Button1Click(Sender: TObject);
var
  ADC : HDC;
  sx, sy : integer;
  bm : TBitmap;
begin
  ADC := GetDC(0);
  bm := TBitmap.Create; //Need a temporary bitmap.
  bm.Width := HarmFade1.Width;
  bm.Height := Harmfade1.Height;
  sx := HarmFade1.ClientOrigin.x;
  sy := HarmFade1.ClientOrigin.y;
  Bitblt(bm.Canvas.Handle, 0, 0, //BitBlt to our temp bmp
  bm.Width, bm.Height,
  ADC, sx, sy, SRCCOPY);
  HarmFade1.PicFrom.Assign(bm); //Assign it to harmfade
//IF harmfade covers other controls, it's best to make them
// invisible here, like Image1.Visible := FALSE;
  HarmFade1.Visible := TRUE; // Sneak us into position
  HarmFade1.Blend; // Show the PicTo
  bm.Free; // Free the temp bmp
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  HarmFade1.Visible := FALSE;
//If other controls were made invisible, reverse it
// here Image1.Visible := TRUE;
end;