View Issue Details

IDProjectCategoryView StatusLast Update
0003967JEDI VCL00 JVCL Componentspublic2007-06-19 03:10
ReportermvrhovAssigned Toobones 
PrioritynormalSeverityfeatureReproducibilityalways
Status resolvedResolutionfixed 
Product VersionDaily / GIT 
Target VersionFixed in Version3.34 
Summary0003967: Refactoring of Desktop Alert to allow displaying custom forms
DescriptionAs said in newsgroup here is refactored DEsktop alert to allow displaying custom forms.

Two things need to be done, create an icon for TJvDesktopAlertForm and registering that new copmonent I beleive that you guys can do that.

Updated example will follow in next few days.
TagsNo tags attached.

Activities

2006-10-22 14:32

 

JvDesktopAlert.diff (41,588 bytes)
--- C:\Documents and Settings\Miha Vrhovnik\Desktop\New Folder (2)\JvDesktopAlert.pas.~1~	Fri Oct 20 10:35:42 2006
+++ C:\Documents and Settings\Miha Vrhovnik\Desktop\New Folder (2)\JvDesktopAlert.pas	Sun Oct 22 22:06:49 2006
@@ -17,6 +17,7 @@
 Contributor(s):
 Hans-Eric Grnlund (stack logic)
 Olivier Sannier (animation styles logic)
+Miha Vrhovnik (http://simail.sf.net)
 
 You may retrieve the latest version of this file at the Project JEDI's JVCL home page,
 located at http://jvcl.sourceforge.net
@@ -146,29 +147,64 @@
   TJvDesktopAlertOption = (daoCanClick, daoCanMove, daoCanMoveAnywhere, daoCanClose);
   TJvDesktopAlertOptions = set of TJvDesktopAlertOption;
 
-  TJvDesktopAlert = class(TJvCommonDialogP)
+  TJvCustomDesktopAlert = class(TJvCommonDialogP)
   private
     FStacker: TJvDesktopAlertStack;
-    FImages: TCustomImageList;
-    FButtons: TJvDesktopAlertButtons;
     FColors: TJvDesktopAlertColors;
     FLocation: TJvDesktopAlertLocation;
     FOptions: TJvDesktopAlertOptions;
+    FAutoFocus: Boolean;
+    FAutoFree: Boolean;
+    FAlertStyle: TJvAlertStyle;
+    FStyleHandler: TJvCustomDesktopAlertStyleHandler;
+
+    function GetStacker: TJvDesktopAlertStack;
+    procedure SetColors(const Value: TJvDesktopAlertColors);
+    function GetAlertStack: TJvDesktopAlertStack;
+    procedure SetAlertStack(const Value: TJvDesktopAlertStack);
+    procedure SetLocation(const Value: TJvDesktopAlertLocation);
+    procedure DoLocationChange(Sender: TObject);
+    procedure SetOptions(const Value: TJvDesktopAlertOptions);
+    procedure SetStyleHandler(const Value: TJvCustomDesktopAlertStyleHandler);
+    procedure SetAlertStyle(const Value: TJvAlertStyle);
+  protected
+    FDesktopForm: TJvCustomFormDesktopAlert;
+    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
+    procedure InternalOnMove(Sender: TObject);
+  public
+    constructor Create(AOwner: TComponent); override;
+    destructor Destroy; override;
+    function Showing: Boolean;
+    procedure Close(Immediate: Boolean);
+    function Execute: Boolean; override;
+    property StyleHandler: TJvCustomDesktopAlertStyleHandler read FStyleHandler write SetStyleHandler;
+  published
+    property AlertStack: TJvDesktopAlertStack read GetAlertStack write SetAlertStack;
+    property AlertStyle: TJvAlertStyle read FAlertStyle write SetAlertStyle default asFade;
+    property AutoFocus: Boolean read FAutoFocus write FAutoFocus default False;
+    property AutoFree: Boolean read FAutoFree write FAutoFree default False;
+
+    property Options: TJvDesktopAlertOptions read FOptions write SetOptions default [daoCanClick..daoCanClose];
+    property Colors: TJvDesktopAlertColors read FColors write SetColors;
+    property Location: TJvDesktopAlertLocation read FLocation write SetLocation;
+
+    // This property is equivalent to StyleHandler, it is just renamed to look better in the inspector
+    property StyleOptions: TJvCustomDesktopAlertStyleHandler read FStyleHandler write SetStyleHandler;
+  end;
+
+  TJvDesktopAlert = class(TJvCustomDesktopAlert)
+  private
+    FImages: TCustomImageList;
+    FButtons: TJvDesktopAlertButtons;
     FOnClose: TNotifyEvent;
     FOnMouseEnter: TNotifyEvent;
     FOnMessageClick: TNotifyEvent;
     FOnShow: TNotifyEvent;
     FOnMouseLeave: TNotifyEvent;
     FData: TObject;
-    FAutoFocus: Boolean;
-    FAutoFree: Boolean;
-    FAlertStyle: TJvAlertStyle;
-    FStyleHandler: TJvCustomDesktopAlertStyleHandler;
     FOnShown: TNotifyEvent;
     FOnShowing: TNotifyEvent;
-    function GetStacker: TJvDesktopAlertStack;
     procedure SetButtons(const Value: TJvDesktopAlertButtons);
-    procedure SetColors(const Value: TJvDesktopAlertColors);
     procedure SetDropDownMenu(const Value: TPopupMenu);
     procedure SetFont(const Value: TFont);
     procedure SetHeaderFont(const Value: TFont);
@@ -182,9 +218,6 @@
     procedure InternalMouseEnter(Sender: TObject);
     procedure InternalMouseLeave(Sender: TObject);
     procedure InternalMessageClick(Sender: TObject);
-    procedure InternalOnMove(Sender: TObject);
-    function GetAlertStack: TJvDesktopAlertStack;
-    procedure SetAlertStack(const Value: TJvDesktopAlertStack);
     function GetFont: TFont;
     function GetHeaderFont: TFont;
     function GetImage: TPicture;
@@ -193,40 +226,39 @@
     function GetMessageText: string;
     function GetPopupMenu: TPopupMenu;
     procedure SetHeaderText(const Value: string);
-    procedure SetLocation(const Value: TJvDesktopAlertLocation);
     procedure SetMessageText(const Value: string);
-    procedure DoLocationChange(Sender: TObject);
     function GetParentFont: Boolean;
     function GetShowHint: Boolean;
     function GetHint: string;
     procedure SetHint(const Value: string);
     procedure SetParentFont(const Value: Boolean);
     procedure SetShowHint(const Value: Boolean);
-    procedure SetOptions(const Value: TJvDesktopAlertOptions);
     function GetCloseButtonClick: TNotifyEvent;
     procedure SetCloseButtonClick(const Value: TNotifyEvent);
-    procedure SetAlertStyle(const Value: TJvAlertStyle);
-    procedure SetStyleHandler(const Value: TJvCustomDesktopAlertStyleHandler);
     function GetBiDiMode: TBidiMode;
     procedure SetBiDiMode(const Value: TBidiMode);
+    function GetDesktopForm: TJvFormDesktopAlert;
+    property DesktopForm: TJvFormDesktopAlert read GetDesktopForm;
   protected
     FFormButtons: array of TControl;
-    FDesktopForm: TJvFormDesktopAlert;
-    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
   public
     constructor Create(AOwner: TComponent); override;
     destructor Destroy; override;
-    function Showing: Boolean;
-    procedure Close(Immediate: Boolean);
     function Execute: Boolean; override;
-    property Form: TJvFormDesktopAlert read FDesktopForm;
+    property Form: TJvCustomFormDesktopAlert read FDesktopForm;
     property Data: TObject read FData write FData;
-    property StyleHandler: TJvCustomDesktopAlertStyleHandler read FStyleHandler write SetStyleHandler;
   published
-    property AlertStack: TJvDesktopAlertStack read GetAlertStack write SetAlertStack;
-    property AlertStyle: TJvAlertStyle read FAlertStyle write SetAlertStyle default asFade;
-    property AutoFocus: Boolean read FAutoFocus write FAutoFocus default False;
-    property AutoFree: Boolean read FAutoFree write FAutoFree default False;
+    property AlertStack;
+    property AlertStyle;
+    property AutoFocus;
+    property AutoFree;
+
+    property Options;
+    property Colors;
+    property Location;
+
+    property StyleOptions;
+
     property BiDiMode: TBidiMode read GetBiDiMode write SetBiDiMode default bdLeftToRight;
     property HeaderText: string read GetHeaderText write SetHeaderText;
     property MessageText: string read GetMessageText write SetMessageText;
@@ -236,18 +268,12 @@
     property ShowHint: Boolean read GetShowHint write SetShowHint;
     property Font: TFont read GetFont write SetFont;
     property ParentFont: Boolean read GetParentFont write SetParentFont;
-    property Options: TJvDesktopAlertOptions read FOptions write SetOptions default [daoCanClick..daoCanClose];
-    property Colors: TJvDesktopAlertColors read FColors write SetColors;
     property Buttons: TJvDesktopAlertButtons read FButtons write SetButtons;
-    property Location: TJvDesktopAlertLocation read FLocation write SetLocation;
     property Image: TPicture read GetImage write SetImage;
     property Images: TCustomImageList read FImages write SetImages;
     property DropDownMenu: TPopupMenu read GetDropDownMenu write SetDropDownMenu;
     property PopupMenu: TPopupMenu read GetPopupMenu write SetPopupMenu;
 
-    // This property is equivalent to StyleHandler, it is just renamed to look better in the inspector
-    property StyleOptions: TJvCustomDesktopAlertStyleHandler read FStyleHandler write SetStyleHandler;
-
     property OnShowing: TNotifyEvent read FOnShowing write FOnShowing;
     property OnShow: TNotifyEvent read FOnShow write FOnShow;
     property OnShown: TNotifyEvent read FOnShown write FOnShown;
@@ -258,12 +284,32 @@
     property OnMessageClick: TNotifyEvent read FOnMessageClick write FOnMessageClick;
   end;
 
+  TJvDesktopAlertForm = class(TJvCustomDesktopAlert)
+  private
+    procedure SetForm(const Value: TJvCustomFormDesktopAlert);
+  protected
+  public
+    property Form: TJvCustomFormDesktopAlert read FDesktopForm write SetForm;
+    function Execute: Boolean; override;
+  published
+    property AlertStack;
+    property AlertStyle;
+    property AutoFocus;
+    property AutoFree;
+
+    property Options;
+    property Colors;
+    property Location;
+
+    property StyleOptions;
+  end;
+
   TJvDesktopAlertStack = class(TJvComponent)
   private
     FItems: TList;
     FPosition: TJvDesktopAlertPosition;
     function GetCount: Integer;
-    function GetItems(Index: Integer): TJvFormDesktopAlert;
+    function GetItems(Index: Integer): TJvCustomFormDesktopAlert;
     procedure SetPosition(const Value: TJvDesktopAlertPosition);
   protected
     procedure UpdatePositions; virtual;
@@ -271,7 +317,7 @@
     procedure Add(AForm: TCustomForm); virtual;
     procedure Remove(AForm: TCustomForm); virtual;
 
-    property Items[Index: Integer]: TJvFormDesktopAlert read GetItems;
+    property Items[Index: Integer]: TJvCustomFormDesktopAlert read GetItems;
     property Count: Integer read GetCount;
     constructor Create(AOwner: TComponent); override;
     destructor Destroy; override;
@@ -280,11 +326,11 @@
     property Position: TJvDesktopAlertPosition read FPosition write SetPosition default dapBottomRight;
   end;
 
-  // Common ancestor of all the alert styles for a TJvFormDesktopAlert
+  // Common ancestor of all the alert styles for a TJvCustomFormDesktopAlert
   TJvCustomDesktopAlertStyleHandler = class(TPersistent)
   private
     FAnimTimer: TTimer;
-    FOwnerForm: TJvFormDesktopAlert;
+    FOwnerForm: TJvCustomFormDesktopAlert;
     FStartSteps: Cardinal;
     FEndSteps: Cardinal;
     FEndInterval: Cardinal;
@@ -293,7 +339,7 @@
     FCurrentStep: Cardinal;
     FStatus: TJvStyleHandlerStatus;
     procedure SetDisplayDuration(const Value: Cardinal);
-    procedure SetOwnerForm(const Value: TJvFormDesktopAlert);
+    procedure SetOwnerForm(const Value: TJvCustomFormDesktopAlert);
     function GetActive: Boolean;
   protected
     procedure SetEndInterval(const Value: Cardinal); virtual;
@@ -334,7 +380,7 @@
     // The timer used for all animations and waits
     property AnimTimer: TTimer read FAnimTimer;
   public
-    constructor Create(OwnerForm: TJvFormDesktopAlert); virtual;
+    constructor Create(OwnerForm: TJvCustomFormDesktopAlert); virtual;
     destructor Destroy; override;
     // Sets up the timer to call StartAnimTimer on the correct interval
     // then show the owner form.
@@ -354,7 +400,7 @@
     procedure AbortAnimation; virtual;
     // The owner form, the form to which the style is associated.
     // This value MUST NOT be nil when any of the DoXXXX function is called
-    property OwnerForm: TJvFormDesktopAlert read FOwnerForm write SetOwnerForm;
+    property OwnerForm: TJvCustomFormDesktopAlert read FOwnerForm write SetOwnerForm;
     // The current step in the animation (starts at 0, use Active to know
     // if an animation or wait is in progress).
     property CurrentStep: Cardinal read FCurrentStep;
@@ -397,7 +443,7 @@
     procedure PrepareEndAnimation; override;
     procedure FinalizeEndAnimation; override;
   public
-    constructor Create(OwnerForm: TJvFormDesktopAlert); override;
+    constructor Create(OwnerForm: TJvCustomFormDesktopAlert); override;
     procedure AbortAnimation; override;
   published
     property MinAlphaBlendValue: Byte read FMinAlphaBlendValue write SetMinAlphaBlendValue default 0;
@@ -426,7 +472,7 @@
     procedure PrepareEndAnimation; override;
     procedure FinalizeEndAnimation; override;
   public
-    constructor Create(OwnerForm: TJvFormDesktopAlert); override;
+    constructor Create(OwnerForm: TJvCustomFormDesktopAlert); override;
     procedure AbortAnimation; override;
   published
     property StartInterval default 25;
@@ -438,7 +484,7 @@
     property MaxGrowthPercentage: Double read FMaxGrowthPercentage write SetMaxGrowthPercentage;
   end;
 
-function CreateHandlerForStyle(Style: TJvAlertStyle; OwnerForm: TJvFormDesktopAlert): TJvCustomDesktopAlertStyleHandler;
+function CreateHandlerForStyle(Style: TJvAlertStyle; OwnerForm: TJvCustomFormDesktopAlert): TJvCustomDesktopAlertStyleHandler;
 
 {$IFDEF UNITVERSIONING}
 const
@@ -459,7 +505,7 @@
 var
   GStacker: TJvDesktopAlertStack = nil;
 
-function CreateHandlerForStyle(Style: TJvAlertStyle; OwnerForm: TJvFormDesktopAlert): TJvCustomDesktopAlertStyleHandler;
+function CreateHandlerForStyle(Style: TJvAlertStyle; OwnerForm: TJvCustomFormDesktopAlert): TJvCustomDesktopAlertStyleHandler;
 begin
   case Style of
     asFade:
@@ -677,10 +723,7 @@
 constructor TJvDesktopAlert.Create(AOwner: TComponent);
 begin
   inherited Create(AOwner);
-  FColors := TJvDesktopAlertColors.Create;
   FButtons := TJvDesktopAlertButtons.Create(Self);
-  FLocation := TJvDesktopAlertLocation.Create;
-  FLocation.OnChange := DoLocationChange;
   FDesktopForm := TJvFormDesktopAlert.Create(Self);
   AlertStyle := asFade;
   FOptions := [daoCanClick..daoCanClose];
@@ -688,174 +731,49 @@
 
 destructor TJvDesktopAlert.Destroy;
 begin
-  // when AutoFreeing, Delphi doesn't like the component having an owner, so remove the Owner here
-  if FAutoFree and (Owner <> nil) and not (csDesigning in ComponentState) then
-    Owner.RemoveComponent(Self);
-  if (FDesktopForm <> nil) then
-  begin
-    if FDesktopForm.Showing then
-      FDesktopForm.Close;
-    FDesktopForm.OnClose := nil;
-    GetStacker.Remove(FDesktopForm);
-    FDesktopForm.Release;
-    FDesktopForm := nil;
-  end;
-  FreeAndNil(FColors);
   FreeAndNil(FButtons);
-  FreeAndNil(FLocation);
-  FreeAndNil(FStyleHandler);
-  inherited Destroy;
-end;
-
-procedure TJvDesktopAlert.Close(Immediate: Boolean);
-begin
-  if Showing then
-  begin
-    if Immediate then
-      FDesktopForm.Close
-    else
-      FStyleHandler.DoEndAnimation;
-  end;
-end;
 
-procedure TJvDesktopAlert.DoLocationChange(Sender: TObject);
-begin
-  if GetStacker.Position <> Location.Position then
-  begin
-    if GetStacker = GlobalStacker then
-      GetStacker.Position := Location.Position
-    else
-      Location.Position := GetStacker.Position;
-  end;
+  inherited Destroy;
 end;
 
 function TJvDesktopAlert.Execute: Boolean;
 var
-  ARect: TRect;
   I, X, Y: Integer;
   FActiveWindow, FActiveFocus: HWND;
-  Position: TJvDesktopAlertPosition;
-
-  procedure CenterForm(AForm: TCustomForm; ARect: TRect);
-  begin
-    AForm.Top := ARect.Top + ((ARect.Bottom - ARect.Top) - AForm.Height) div 2;
-    AForm.Left := ARect.Left + ((ARect.Right - ARect.Left) - AForm.Width) div 2;
-  end;
-
 begin
-  Assert(FDesktopForm <> nil);
-  if FDesktopForm.Visible then
-    FDesktopForm.Close;
-
-  ARect := ScreenWorkArea;
-  if (Application <> nil) and (Application.MainForm <> nil) and
-     (Location.Position in [dapMainFormTopLeft, dapMainFormTopRight, dapMainFormBottomLeft, dapMainFormBottomRight]) then
-    ARect := Application.MainForm.BoundsRect
-  else
-  if (Screen.ActiveForm <> nil) and
-     (Location.Position in [dapActiveFormTopLeft, dapActiveFormTopRight, dapActiveFormBottomLeft, dapActiveFormBottomRight]) then
-    ARect := Screen.ActiveForm.BoundsRect
-  else
-  if (Owner is TCustomForm) and
-     (Location.Position in [dapOwnerFormTopLeft, dapOwnerFormTopRight, dapOwnerFormBottomLeft, dapOwnerFormBottomRight]) then
-    ARect := TCustomForm(Owner).BoundsRect;
-
-  Position := Location.Position;
-  case Position of
-    dapMainFormTopLeft, dapActiveFormTopLeft, dapOwnerFormTopLeft:
-      Position := dapTopLeft;
-    dapMainFormTopRight, dapActiveFormTopRight, dapOwnerFormTopRight:
-      Position := dapTopRight;
-    dapMainFormBottomLeft, dapActiveFormBottomLeft, dapOwnerFormBottomLeft:
-      Position := dapBottomLeft;
-    dapMainFormBottomRight, dapActiveFormBottomRight, dapOwnerFormBottomRight:
-      Position := dapBottomRight;
-  end;
-
-  if Location.Width <> 0 then
-    FDesktopForm.Width := Location.Width
-  else
-    FDesktopForm.Width := cDefaultAlertFormWidth;
-  if Location.Height <> 0 then
-    FDesktopForm.Height := Location.Height
-  else
-    FDesktopForm.Height := cDefaultAlertFormHeight;
-  case Position of
-    dapTopLeft:
-      begin
-        FDesktopForm.Top := ARect.Top;
-        FDesktopForm.Left := ARect.Left;
-      end;
-    dapTopRight:
-      begin
-        FDesktopForm.Top := ARect.Top;
-        FDesktopForm.Left := ARect.Right - FDesktopForm.Width;
-      end;
-    dapBottomLeft:
-      begin
-        FDesktopForm.Top := ARect.Bottom - FDesktopForm.Height;
-        FDesktopForm.Left := ARect.Left;
-      end;
-    dapBottomRight:
-      begin
-        FDesktopForm.Top := ARect.Bottom - FDesktopForm.Height;
-        FDesktopForm.Left := ARect.Right - FDesktopForm.Width;
-      end;
-    dapCustom:
-      begin
-        FDesktopForm.Top := Location.Top;
-        FDesktopForm.Left := Location.Left;
-      end;
-    dapDesktopCenter, dapMainFormCenter, dapOwnerFormCenter, dapActiveFormCenter:
-      begin
-        CenterForm(FDesktopForm, ARect);
-        if (Location.Position = dapActiveFormCenter) and (Screen.ActiveForm <> nil) then
-          CenterForm(FDesktopForm, Screen.ActiveForm.BoundsRect)
-        else
-        if (Location.Position = dapMainFormCenter) and (Application <> nil) and (Application.MainForm <> nil) then
-          CenterForm(FDesktopForm, Application.MainForm.BoundsRect)
-        else
-        if (Location.Position = dapOwnerFormCenter) and (Owner is TCustomForm) then
-          CenterForm(FDesktopForm, TCustomForm(Owner).BoundsRect);
-      end;
-  end;
+  inherited Execute;
 
-  FDesktopForm.OnShowing := InternalOnShowing;
-  FDesktopForm.OnShow    := InternalOnShow;
-  FDesktopForm.OnShown   := InternalOnShown;
-  FDesktopForm.OnClose := InternalOnClose;
-  FDesktopForm.OnMouseEnter := InternalMouseEnter;
-  FDesktopForm.OnMouseLeave := InternalMouseLeave;
-  FDesktopForm.OnUserMove := InternalOnMove;
-  FDesktopForm.lblText.OnClick := InternalMessageClick;
-  FDesktopForm.Moveable := (daoCanMove in Options);
-  FDesktopForm.MoveAnywhere := (daoCanMoveAnywhere in Options);
-  FDesktopForm.Closeable := (daoCanClose in Options);
-  FDesktopForm.ClickableMessage := daoCanClick in Options;
-  if not Assigned(FDesktopForm.tbClose.OnClick) then
-    FDesktopForm.tbClose.OnClick := FDesktopForm.acCloseExecute;
-
-  FDesktopForm.tbDropDown.DropDownMenu := DropDownMenu;
-  FDesktopForm.imIcon.Picture := Image;
-
-  FDesktopForm.Font := Font;
-  FDesktopForm.lblHeader.Caption := HeaderText;
-  FDesktopForm.lblHeader.Font := HeaderFont;
-  FDesktopForm.lblText.Caption := MessageText;
-  FDesktopForm.WindowColorFrom := Colors.WindowFrom;
-  FDesktopForm.WindowColorTo := Colors.WindowTo;
-  FDesktopForm.CaptionColorFrom := Colors.CaptionFrom;
-  FDesktopForm.CaptionColorTo := Colors.CaptionTo;
-  FDesktopForm.FrameColor := Colors.Frame;
+  DesktopForm.OnShowing := InternalOnShowing;
+  DesktopForm.OnShow    := InternalOnShow;
+  DesktopForm.OnShown   := InternalOnShown;
+  DesktopForm.OnClose := InternalOnClose;
+  DesktopForm.OnMouseEnter := InternalMouseEnter;
+  DesktopForm.OnMouseLeave := InternalMouseLeave;
+  DesktopForm.OnUserMove := InternalOnMove;
+  DesktopForm.lblText.OnClick := InternalMessageClick;
+  DesktopForm.Moveable := (daoCanMove in Options);
+  DesktopForm.MoveAnywhere := (daoCanMoveAnywhere in Options);
+  DesktopForm.Closeable := (daoCanClose in Options);
+  DesktopForm.ClickableMessage := daoCanClick in Options;
+  if not Assigned(DesktopForm.tbClose.OnClick) then
+    DesktopForm.tbClose.OnClick := DesktopForm.acCloseExecute;
+
+  DesktopForm.tbDropDown.DropDownMenu := DropDownMenu;
+  DesktopForm.imIcon.Picture := Image;
+
+  DesktopForm.Font := Font;
+  DesktopForm.lblHeader.Caption := HeaderText;
+  DesktopForm.lblHeader.Font := HeaderFont;
+  DesktopForm.lblText.Caption := MessageText;
 
   for I := 0 to Length(FFormButtons) - 1 do
     FFormButtons[I].Free;
   SetLength(FFormButtons, Buttons.Count);
   X := 2;
-  Y := FDesktopForm.Height - 23;
+  Y := DesktopForm.Height - 23;
   for I := 0 to Length(FFormButtons) - 1 do
   begin
-    FFormButtons[I] := TJvDesktopAlertButton.Create(FDesktopForm);
+    FFormButtons[I] := TJvDesktopAlertButton.Create(DesktopForm);
     with TJvDesktopAlertButton(FFormButtons[I]) do
     begin
       SetBounds(X, Y, 21, 21);
@@ -864,8 +782,8 @@
       ImageIndex := Buttons[I].ImageIndex;
       Tag := Buttons[I].Tag;
       InternalClick := Buttons[I].OnClick;
-      OnClick := FDesktopForm.DoButtonClick;
-      Parent := FDesktopForm;
+      OnClick := DesktopForm.DoButtonClick;
+      Parent := DesktopForm;
       Inc(X, 22);
     end;
   end;
@@ -880,8 +798,8 @@
     FActiveWindow := NullHandle;
     FActiveFocus := NullHandle;
   end;
-  FDesktopForm.AllowFocus := AutoFocus;
-  FDesktopForm.ShowNoActivate;
+  DesktopForm.AllowFocus := AutoFocus;
+  DesktopForm.ShowNoActivate;
   Result := True;
   if not AutoFocus and (FActiveFocus <> GetFocus) then
   begin
@@ -891,73 +809,62 @@
     if (FActiveWindow <> NullHandle) then
       SetActiveWindow(FActiveWindow);
   end;
-  GetStacker.Add(FDesktopForm);
+  GetStacker.Add(DesktopForm);
 end;
 
-function TJvDesktopAlert.GetAlertStack: TJvDesktopAlertStack;
+function TJvDesktopAlert.GetDesktopForm: TJvFormDesktopAlert;
 begin
-  if FStacker = GlobalStacker then
-    Result := nil
-  else
-    Result := FStacker;
+  Result := TJvFormDesktopAlert(FDesktopForm);
 end;
 
 function TJvDesktopAlert.GetDropDownMenu: TPopupMenu;
 begin
-  Result := FDesktopForm.tbDropDown.DropDownMenu;
+  Result := DesktopForm.tbDropDown.DropDownMenu;
 end;
 
 function TJvDesktopAlert.GetFont: TFont;
 begin
-  Result := FDesktopForm.lblText.Font;
+  Result := DesktopForm.lblText.Font;
 end;
 
 function TJvDesktopAlert.GetHeaderFont: TFont;
 begin
-  Result := FDesktopForm.lblHeader.Font;
+  Result := DesktopForm.lblHeader.Font;
 end;
 
 function TJvDesktopAlert.GetHeaderText: string;
 begin
-  Result := FDesktopForm.lblHeader.Caption;
+  Result := DesktopForm.lblHeader.Caption;
 end;
 
 function TJvDesktopAlert.GetImage: TPicture;
 begin
-  Result := FDesktopForm.imIcon.Picture;
+  Result := DesktopForm.imIcon.Picture;
 end;
 
 function TJvDesktopAlert.GetMessageText: string;
 begin
-  Result := FDesktopForm.lblText.Caption;
+  Result := DesktopForm.lblText.Caption;
 end;
 
 function TJvDesktopAlert.GetParentFont: Boolean;
 begin
-  Result := FDesktopForm.ParentFont;
+  Result := DesktopForm.ParentFont;
 end;
 
 function TJvDesktopAlert.GetPopupMenu: TPopupMenu;
 begin
-  Result := FDesktopForm.PopupMenu;
+  Result := DesktopForm.PopupMenu;
 end;
 
 function TJvDesktopAlert.GetShowHint: Boolean;
 begin
-  Result := FDesktopForm.ShowHint;
-end;
-
-function TJvDesktopAlert.GetStacker: TJvDesktopAlertStack;
-begin
-  if FStacker = nil then
-    Result := GlobalStacker
-  else
-    Result := FStacker;
+  Result := DesktopForm.ShowHint;
 end;
 
 function TJvDesktopAlert.GetHint: string;
 begin
-  Result := FDesktopForm.Hint;
+  Result := DesktopForm.Hint;
 end;
 
 procedure TJvDesktopAlert.InternalMessageClick(Sender: TObject);
@@ -973,7 +880,7 @@
     finally
       StyleHandler.EndInterval := FEndInterval;
     end;
-    if not Form.MouseInControl then
+    if not DesktopForm.MouseInControl then
       StyleHandler.DoEndAnimation;
   end;
 end;
@@ -997,32 +904,22 @@
     Exit;
   if Location.Position = dapCustom then
   begin
-    Location.Top := FDesktopForm.Top;
-    Location.Left := FDesktopForm.Left;
+    Location.Top := DesktopForm.Top;
+    Location.Left := DesktopForm.Left;
   end;
   if Assigned(FOnClose) then
     FOnClose(Self);
-  GetStacker.Remove(FDesktopForm);
-  if AutoFree and (FDesktopForm <> nil) and not (csDesigning in ComponentState) then
+  GetStacker.Remove(DesktopForm);
+  if AutoFree and (DesktopForm <> nil) and not (csDesigning in ComponentState) then
   begin
-    FDesktopForm.OnClose := nil;
+    DesktopForm.OnClose := nil;
     // post a message to the form so we have time to finish off all event handlers and
     // timers before the form and component are freed
-    PostMessage(FDesktopForm.Handle, JVDESKTOPALERT_AUTOFREE, WPARAM(FDesktopForm), LPARAM(Self));
+    PostMessage(DesktopForm.Handle, JVDESKTOPALERT_AUTOFREE, WPARAM(DesktopForm), LPARAM(Self));
     FDesktopForm := nil;
   end;
 end;
 
-procedure TJvDesktopAlert.InternalOnMove(Sender: TObject);
-begin
-  if not (csDesigning in ComponentState) and not Location.AlwaysResetPosition and
-    (Location.Position <> dapCustom) then
-  begin
-    GetStacker.Remove(FDesktopForm);
-    Location.Position := dapCustom;
-  end;
-end;
-
 procedure TJvDesktopAlert.InternalOnShow(Sender: TObject);
 begin
   if Assigned(FOnShow) then
@@ -1041,68 +938,39 @@
     FOnShown(Self);
 end;
 
-procedure TJvDesktopAlert.Notification(AComponent: TComponent;
-  Operation: TOperation);
+procedure TJvDesktopAlert.SetButtons(const Value: TJvDesktopAlertButtons);
 begin
-  inherited Notification(AComponent, Operation);
-  if Operation = opRemove then
-  begin
-    if AComponent = FStacker then
-      AlertStack := nil;
-  end;
+  FButtons.Assign(Value);
 end;
 
-procedure TJvDesktopAlert.SetAlertStack(const Value: TJvDesktopAlertStack);
+procedure TJvDesktopAlert.SetDropDownMenu(const Value: TPopupMenu);
 begin
-  if FStacker <> Value then
-  begin
-    FStacker := Value;
-    if FStacker <> nil then
-    begin
-      Location.Position := FStacker.Position;
-      FStacker.FreeNotification(Self);
-    end;
-  end;
-end;
-
-procedure TJvDesktopAlert.SetButtons(const Value: TJvDesktopAlertButtons);
-begin
-  FButtons.Assign(Value);
-end;
-
-procedure TJvDesktopAlert.SetColors(const Value: TJvDesktopAlertColors);
-begin
-  FColors.Assign(Value);
-end;
-
-procedure TJvDesktopAlert.SetDropDownMenu(const Value: TPopupMenu);
-begin
-  FDesktopForm.tbDropDown.DropDownMenu := Value;
+  DesktopForm.tbDropDown.DropDownMenu := Value;
 end;
 
 procedure TJvDesktopAlert.SetFont(const Value: TFont);
 begin
-  FDesktopForm.lblText.Font := Value;
+  DesktopForm.lblText.Font := Value;
 end;
 
 procedure TJvDesktopAlert.SetHeaderFont(const Value: TFont);
 begin
-  FDesktopForm.lblHeader.Font := Value;
+  DesktopForm.lblHeader.Font := Value;
 end;
 
 procedure TJvDesktopAlert.SetHeaderText(const Value: string);
 begin
-  FDesktopForm.lblHeader.Caption := Value;
+  DesktopForm.lblHeader.Caption := Value;
 end;
 
 procedure TJvDesktopAlert.SetHint(const Value: string);
 begin
-  FDesktopForm.Hint := Value;
+  DesktopForm.Hint := Value;
 end;
 
 procedure TJvDesktopAlert.SetImage(const Value: TPicture);
 begin
-  FDesktopForm.imIcon.Picture := Value;
+  DesktopForm.imIcon.Picture := Value;
 end;
 
 procedure TJvDesktopAlert.SetImages(const Value: TCustomImageList);
@@ -1115,65 +983,35 @@
   end;
 end;
 
-procedure TJvDesktopAlert.SetLocation(const Value: TJvDesktopAlertLocation);
-begin
-  //
-end;
-
 procedure TJvDesktopAlert.SetMessageText(const Value: string);
 begin
-  FDesktopForm.lblText.Caption := Value;
-  FDesktopForm.lblText.Update;
+  DesktopForm.lblText.Caption := Value;
+  DesktopForm.lblText.Update;
 end;
 
 procedure TJvDesktopAlert.SetParentFont(const Value: Boolean);
 begin
-  FDesktopForm.ParentFont := Value;
+  DesktopForm.ParentFont := Value;
 end;
 
 procedure TJvDesktopAlert.SetPopupMenu(const Value: TPopupMenu);
 begin
-  FDesktopForm.PopupMenu := Value;
+  DesktopForm.PopupMenu := Value;
 end;
 
 procedure TJvDesktopAlert.SetShowHint(const Value: Boolean);
 begin
-  FDesktopForm.ShowHint := Value;
-end;
-
-function TJvDesktopAlert.Showing: Boolean;
-begin
-  Result := (FDesktopForm <> nil) and FDesktopForm.Showing;
-end;
-
-procedure TJvDesktopAlert.SetOptions(const Value: TJvDesktopAlertOptions);
-begin
-  if FOptions <> Value then
-  begin
-    FOptions := Value;
-    if not (daoCanMove in FOptions) then
-      Exclude(FOptions, daoCanMoveAnywhere);
-  end;
+  DesktopForm.ShowHint := Value;
 end;
 
 function TJvDesktopAlert.GetCloseButtonClick: TNotifyEvent;
 begin
-  Result := FDesktopForm.tbClose.OnClick;
+  Result := DesktopForm.tbClose.OnClick;
 end;
 
 procedure TJvDesktopAlert.SetCloseButtonClick(const Value: TNotifyEvent);
 begin
-  FDesktopForm.tbClose.OnClick := Value;
-end;
-
-procedure TJvDesktopAlert.SetAlertStyle(const Value: TJvAlertStyle);
-begin
-  if (FAlertStyle <> Value) or (FStyleHandler = nil) then
-  begin
-    FAlertStyle := Value;
-    FStyleHandler.Free;
-    FStyleHandler := CreateHandlerForStyle(AlertStyle, FDesktopForm);
-  end;
+  DesktopForm.tbClose.OnClick := Value;
 end;
 
 //=== { TJvDesktopAlertStack } ===============================================
@@ -1202,18 +1040,18 @@
   Result := FItems.Count;
 end;
 
-function TJvDesktopAlertStack.GetItems(Index: Integer): TJvFormDesktopAlert;
+function TJvDesktopAlertStack.GetItems(Index: Integer): TJvCustomFormDesktopAlert;
 begin
-  Result := TJvFormDesktopAlert(FItems[Index]);
-  Assert((Result = nil) or (Result is TJvFormDesktopAlert));
+  Result := TJvCustomFormDesktopAlert(FItems[Index]);
+  Assert((Result = nil) or (Result is TJvCustomFormDesktopAlert));
 end;
 
 procedure TJvDesktopAlertStack.Remove(AForm: TCustomForm);
 var
   Index, PrevNilSlot: Integer;
-  Form: TJvFormDesktopAlert;
+  Form: TJvCustomFormDesktopAlert;
 begin
-  if (AForm <> nil) and (AForm is TJvFormDesktopAlert) then
+  if (AForm <> nil) and (AForm is TJvCustomFormDesktopAlert) then
   begin
     // The basic trick here is to push piling forms down in the list, while keeping the
     // static ones (i.e. a form that has the mouse pointer over it) in place.
@@ -1260,7 +1098,7 @@
 procedure TJvDesktopAlertStack.UpdatePositions;
 var
   C, I: Integer;
-  Form: TJvFormDesktopAlert;
+  Form: TJvCustomFormDesktopAlert;
   X, Y: Integer;
   R: TRect;
 begin
@@ -1331,7 +1169,7 @@
 
 //=== { TJvCustomDesktopAlertStyle } =========================================
 
-constructor TJvCustomDesktopAlertStyleHandler.Create(OwnerForm: TJvFormDesktopAlert);
+constructor TJvCustomDesktopAlertStyleHandler.Create(OwnerForm: TJvCustomFormDesktopAlert);
 begin
   inherited Create;
   FAnimTimer := TTimer.Create(nil);
@@ -1437,7 +1275,7 @@
 end;
 
 procedure TJvCustomDesktopAlertStyleHandler.SetOwnerForm(
-  const Value: TJvFormDesktopAlert);
+  const Value: TJvCustomFormDesktopAlert);
 begin
   FOwnerForm := Value;
 end;
@@ -1488,7 +1326,7 @@
   TDynamicSetLayeredWindowAttributes =
     function(HWnd: THandle; crKey: COLORREF; bAlpha: Byte; dwFlags: DWORD): Boolean; stdcall;
 
-constructor TJvFadeAlertStyleHandler.Create(OwnerForm: TJvFormDesktopAlert);
+constructor TJvFadeAlertStyleHandler.Create(OwnerForm: TJvCustomFormDesktopAlert);
 begin
   inherited Create(OwnerForm);
 
@@ -1590,14 +1428,9 @@
   inherited StartAnimTimer(Sender);
 end;
 
-procedure TJvDesktopAlert.SetStyleHandler(const Value: TJvCustomDesktopAlertStyleHandler);
-begin
-  FStyleHandler.Assign(Value);
-end;
-
 //=== { TJvCenterGrowAlertStyleHandler } =====================================
 
-constructor TJvCenterGrowAlertStyleHandler.Create(OwnerForm: TJvFormDesktopAlert);
+constructor TJvCenterGrowAlertStyleHandler.Create(OwnerForm: TJvCustomFormDesktopAlert);
 begin
   inherited Create(OwnerForm);
 
@@ -1705,6 +1538,292 @@
 procedure TJvDesktopAlert.SetBiDiMode(const Value: TBidiMode);
 begin
   FDesktopForm.BiDiMode := Value;
+end;
+
+{ TJvCustomDesktopAlert }
+
+procedure TJvCustomDesktopAlert.Close(Immediate: Boolean);
+begin
+  if Showing then
+  begin
+    if Immediate then
+      FDesktopForm.Close
+    else
+      FStyleHandler.DoEndAnimation;
+  end;
+end;
+
+constructor TJvCustomDesktopAlert.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner);
+  FColors := TJvDesktopAlertColors.Create;
+  FLocation := TJvDesktopAlertLocation.Create;
+  FLocation.OnChange := DoLocationChange;
+  AlertStyle := asFade;
+  FOptions := [daoCanClick..daoCanClose];
+end;
+
+destructor TJvCustomDesktopAlert.Destroy;
+begin
+  // when AutoFreeing, Delphi doesn't like the component having an owner, so remove the Owner here
+  if FAutoFree and (Owner <> nil) and not (csDesigning in ComponentState) then
+    Owner.RemoveComponent(Self);
+  if (FDesktopForm <> nil) then
+  begin
+    if FDesktopForm.Showing then
+      FDesktopForm.Close;
+    FDesktopForm.OnClose := nil;
+    GetStacker.Remove(FDesktopForm);
+    FDesktopForm.Release;
+    FDesktopForm := nil;
+  end;
+  FreeAndNil(FColors);
+  FreeAndNil(FLocation);
+  FreeAndNil(FStyleHandler);
+  inherited Destroy;
+end;
+
+procedure TJvCustomDesktopAlert.DoLocationChange(Sender: TObject);
+begin
+  if GetStacker.Position <> Location.Position then
+  begin
+    if GetStacker = GlobalStacker then
+      GetStacker.Position := Location.Position
+    else
+      Location.Position := GetStacker.Position;
+  end;
+end;
+
+function TJvCustomDesktopAlert.Execute: Boolean;
+var
+  ARect: TRect;
+  Position: TJvDesktopAlertPosition;
+
+  procedure CenterForm(AForm: TCustomForm; ARect: TRect);
+  begin
+    AForm.Top := ARect.Top + ((ARect.Bottom - ARect.Top) - AForm.Height) div 2;
+    AForm.Left := ARect.Left + ((ARect.Right - ARect.Left) - AForm.Width) div 2;
+  end;
+begin
+  Assert(FDesktopForm <> nil);
+  if FDesktopForm.Visible then
+    FDesktopForm.Close;
+
+  ARect := ScreenWorkArea;
+  if (Application <> nil) and (Application.MainForm <> nil) and
+     (Location.Position in [dapMainFormTopLeft, dapMainFormTopRight, dapMainFormBottomLeft, dapMainFormBottomRight]) then
+    ARect := Application.MainForm.BoundsRect
+  else
+  if (Screen.ActiveForm <> nil) and
+     (Location.Position in [dapActiveFormTopLeft, dapActiveFormTopRight, dapActiveFormBottomLeft, dapActiveFormBottomRight]) then
+    ARect := Screen.ActiveForm.BoundsRect
+  else
+  if (Owner is TCustomForm) and
+     (Location.Position in [dapOwnerFormTopLeft, dapOwnerFormTopRight, dapOwnerFormBottomLeft, dapOwnerFormBottomRight]) then
+    ARect := TCustomForm(Owner).BoundsRect;
+
+  Position := Location.Position;
+  case Position of
+    dapMainFormTopLeft, dapActiveFormTopLeft, dapOwnerFormTopLeft:
+      Position := dapTopLeft;
+    dapMainFormTopRight, dapActiveFormTopRight, dapOwnerFormTopRight:
+      Position := dapTopRight;
+    dapMainFormBottomLeft, dapActiveFormBottomLeft, dapOwnerFormBottomLeft:
+      Position := dapBottomLeft;
+    dapMainFormBottomRight, dapActiveFormBottomRight, dapOwnerFormBottomRight:
+      Position := dapBottomRight;
+  end;
+
+  if Location.Width <> 0 then
+    FDesktopForm.Width := Location.Width
+  else
+    FDesktopForm.Width := cDefaultAlertFormWidth;
+  if Location.Height <> 0 then
+    FDesktopForm.Height := Location.Height
+  else
+    FDesktopForm.Height := cDefaultAlertFormHeight;
+  case Position of
+    dapTopLeft:
+      begin
+        FDesktopForm.Top := ARect.Top;
+        FDesktopForm.Left := ARect.Left;
+      end;
+    dapTopRight:
+      begin
+        FDesktopForm.Top := ARect.Top;
+        FDesktopForm.Left := ARect.Right - FDesktopForm.Width;
+      end;
+    dapBottomLeft:
+      begin
+        FDesktopForm.Top := ARect.Bottom - FDesktopForm.Height;
+        FDesktopForm.Left := ARect.Left;
+      end;
+    dapBottomRight:
+      begin
+        FDesktopForm.Top := ARect.Bottom - FDesktopForm.Height;
+        FDesktopForm.Left := ARect.Right - FDesktopForm.Width;
+      end;
+    dapCustom:
+      begin
+        FDesktopForm.Top := Location.Top;
+        FDesktopForm.Left := Location.Left;
+      end;
+    dapDesktopCenter, dapMainFormCenter, dapOwnerFormCenter, dapActiveFormCenter:
+      begin
+        CenterForm(FDesktopForm, ARect);
+        if (Location.Position = dapActiveFormCenter) and (Screen.ActiveForm <> nil) then
+          CenterForm(FDesktopForm, Screen.ActiveForm.BoundsRect)
+        else
+        if (Location.Position = dapMainFormCenter) and (Application <> nil) and (Application.MainForm <> nil) then
+          CenterForm(FDesktopForm, Application.MainForm.BoundsRect)
+        else
+        if (Location.Position = dapOwnerFormCenter) and (Owner is TCustomForm) then
+          CenterForm(FDesktopForm, TCustomForm(Owner).BoundsRect);
+      end;
+  end;
+
+  FDesktopForm.Moveable := (daoCanMove in Options);
+  FDesktopForm.MoveAnywhere := (daoCanMoveAnywhere in Options);
+  FDesktopForm.WindowColorFrom := Colors.WindowFrom;
+  FDesktopForm.WindowColorTo := Colors.WindowTo;
+  FDesktopForm.CaptionColorFrom := Colors.CaptionFrom;
+  FDesktopForm.CaptionColorTo := Colors.CaptionTo;
+  FDesktopForm.FrameColor := Colors.Frame;
+
+  Result := True;
+end;
+
+function TJvCustomDesktopAlert.GetAlertStack: TJvDesktopAlertStack;
+begin
+  if FStacker = GlobalStacker then
+    Result := nil
+  else
+    Result := FStacker;
+end;
+
+function TJvCustomDesktopAlert.GetStacker: TJvDesktopAlertStack;
+begin
+  if FStacker = nil then
+    Result := GlobalStacker
+  else
+    Result := FStacker;
+end;
+
+procedure TJvCustomDesktopAlert.InternalOnMove(Sender: TObject);
+begin
+  if not (csDesigning in ComponentState) and not Location.AlwaysResetPosition and
+    (Location.Position <> dapCustom) then
+  begin
+    GetStacker.Remove(FDesktopForm);
+    Location.Position := dapCustom;
+  end;
+end;
+
+procedure TJvCustomDesktopAlert.Notification(AComponent: TComponent;
+  Operation: TOperation);
+begin
+  inherited Notification(AComponent, Operation);
+  if Operation = opRemove then
+  begin
+    if AComponent = FStacker then
+      AlertStack := nil;
+  end;
+end;
+
+procedure TJvCustomDesktopAlert.SetAlertStack(const Value: TJvDesktopAlertStack);
+begin
+  if FStacker <> Value then
+  begin
+    FStacker := Value;
+    if FStacker <> nil then
+    begin
+      Location.Position := FStacker.Position;
+      FStacker.FreeNotification(Self);
+    end;
+  end;
+end;
+
+procedure TJvCustomDesktopAlert.SetAlertStyle(const Value: TJvAlertStyle);
+begin
+  FAlertStyle := Value;
+  FStyleHandler.Free;
+  FStyleHandler := CreateHandlerForStyle(AlertStyle, TJvCustomFormDesktopAlert(FDesktopForm));
+end;
+
+procedure TJvCustomDesktopAlert.SetColors(const Value: TJvDesktopAlertColors);
+begin
+  FColors.Assign(Value);
+end;
+
+procedure TJvCustomDesktopAlert.SetLocation(const Value: TJvDesktopAlertLocation);
+begin
+  //
+end;
+
+procedure TJvCustomDesktopAlert.SetOptions(const Value: TJvDesktopAlertOptions);
+begin
+  if FOptions <> Value then
+  begin
+    FOptions := Value;
+    if not (daoCanMove in FOptions) then
+      Exclude(FOptions, daoCanMoveAnywhere);
+  end;
+end;
+
+procedure TJvCustomDesktopAlert.SetStyleHandler(const Value: TJvCustomDesktopAlertStyleHandler);
+begin
+  FStyleHandler.Assign(Value);
+end;
+
+function TJvCustomDesktopAlert.Showing: Boolean;
+begin
+  Result := (FDesktopForm <> nil) and FDesktopForm.Showing;
+end;
+
+{ TJvDesktopAlertForm }
+
+function TJvDesktopAlertForm.Execute: Boolean;
+var
+  FActiveWindow, FActiveFocus: HWND;
+begin
+  inherited Execute;
+  FDesktopForm.Closeable := (daoCanClose in Options);
+  FDesktopForm.OnUserMove := InternalOnMove;
+
+  Location.Position := GetStacker.Position;
+  if not AutoFocus then
+  begin
+    FActiveFocus := GetFocus;
+    FActiveWindow := GetActiveWindow;
+  end
+  else
+  begin
+    FActiveWindow := NullHandle;
+    FActiveFocus := NullHandle;
+  end;
+  FDesktopForm.AllowFocus := AutoFocus;
+  FDesktopForm.ShowNoActivate;
+  Result := True;
+  if not AutoFocus and (FActiveFocus <> GetFocus) then
+  begin
+    if (FActiveFocus <> NullHandle) then
+      SetFocus(FActiveFocus)
+    else
+    if (FActiveWindow <> NullHandle) then
+      SetActiveWindow(FActiveWindow);
+  end;
+  GetStacker.Add(FDesktopForm);
+end;
+
+procedure TJvDesktopAlertForm.SetForm(const Value: TJvCustomFormDesktopAlert);
+begin
+  FDesktopForm := Value;
+  if Value <> nil then begin
+    Location.Width := FDesktopForm.Width;
+    Location.Height := FDesktopForm.Height;
+  end;
+  //reforce alert style so proper form will be assigned to alert displayer
+  AlertStyle := AlertStyle;
 end;
 
 initialization
JvDesktopAlert.diff (41,588 bytes)

2006-10-22 14:32

 

JvDesktopAlertForm.diff (16,027 bytes)
--- C:\Documents and Settings\Miha Vrhovnik\Desktop\New Folder (2)\JvDesktopAlertForm.pas	Sun Oct 22 22:06:56 2006
+++ C:\Documents and Settings\Miha Vrhovnik\Desktop\New Folder (2)\JvDesktopAlertForm.pas.~1~	Fri Oct 20 10:35:42 2006
@@ -17,7 +17,6 @@
 Contributor(s):
 Hans-Eric Gr�nlund (stack logic)
 Olivier Sannier (animation styles logic)
-Miha Vrhovnik (http://simail.sf.net)
 
 You may retrieve the latest version of this file at the Project JEDI's JVCL home page,
 located at http://jvcl.sourceforge.net
@@ -81,18 +80,20 @@
     property OnClick;
   end;
 
-  //we have to inherit from TJvExForm instead from TJvExCustmForm
-  //because otherwise our cusom forms cannot be loaded (we get bunch of Property not exists exceptions)
-  TJvCustomFormDesktopAlert = class(TJvExForm)
+  TJvFormDesktopAlert = class(TJvExCustomForm)
   private
     FOnMouseLeave: TNotifyEvent;
     FOnMouseEnter: TNotifyEvent;
     FOnUserMove: TNotifyEvent;
+    acClose: TAction;
     MouseTimer: TTimer;
+    FEndInterval:Cardinal;
+    FMouseInControl: Boolean;
     FCloseable: Boolean;
     FMoveable: Boolean;
     FMoveAnywhere: Boolean;
     FAllowFocus: Boolean;
+    FClickableMessage: Boolean;
     FCaptionColorTo: TColor;
     FWindowColorTo: TColor;
     FWindowColorFrom: TColor;
@@ -100,8 +101,6 @@
     FFrameColor: TColor;
     FOnShown: TNotifyEvent;
     FOnShowing: TNotifyEvent;
-    FEndInterval:Cardinal;
-    FMouseInControl: Boolean;
     {$IFDEF VCL}
     procedure WMNCHitTest(var Msg: TWMNCHitTest); message WM_NCHITTEST;
     procedure WMActivate(var Message: TWMActivate); message WM_ACTIVATE;
@@ -113,24 +112,33 @@
     procedure FormPaint(Sender: TObject);
     function GetVisible: Boolean;
   protected
-    acClose: TAction;
     procedure DoShow; override;
     procedure DoClose(var Action: TCloseAction); override;
     procedure MouseEnter(AControl: TControl); override;
     procedure MouseLeave(AControl: TControl); override;
-    //override this one if you'd like to exes sth before form is shown
-    procedure InternalDoShow; virtual;
+    procedure DoDropDownClose(Sender: TObject);
+    procedure DoDropDownMenu(Sender: TObject; MousePos: TPoint; var Handled: Boolean);
+
+  public
+    imIcon: TImage;
+    lblText: TJvLabel;
+    lblHeader: TLabel;
+    tbDropDown: TJvDesktopAlertButton;
+    tbClose: TJvDesktopAlertButton;
+
   public
     constructor Create(AOwner: TComponent); override;
     procedure acCloseExecute(Sender: TObject);
     procedure SetNewTop(const Value: Integer);
     procedure SetNewLeft(const Value: Integer);
     procedure SetNewOrigin(ALeft, ATop: Integer);
+    procedure DoButtonClick(Sender: TObject);
     procedure ShowNoActivate;
-
+    
     property Moveable: Boolean read FMoveable write FMoveable;
     property MoveAnywhere: Boolean read FMoveAnywhere write FMoveAnywhere;
     property Closeable: Boolean read FCloseable write FCloseable;
+    property ClickableMessage: Boolean read FClickableMessage write FClickableMessage;
     property MouseInControl: Boolean read FMouseInControl;
     property WindowColorFrom: TColor read FWindowColorFrom write FWindowColorFrom;
     property WindowColorTo: TColor read FWindowColorTo write FWindowColorTo;
@@ -144,36 +152,12 @@
     property OnMouseEnter: TNotifyEvent read FOnMouseEnter write FOnMouseEnter;
     property OnMouseLeave: TNotifyEvent read FOnMouseLeave write FOnMouseLeave;
     property OnUserMove: TNotifyEvent read FOnUserMove write FOnUserMove;
-    property OnClose;
-    property OnShowing: TNotifyEvent read FOnShowing write FOnShowing;
-    property OnShow;
-    property OnShown: TNotifyEvent read FOnShown write FOnShown;
-  end;
-
-  TJvFormDesktopAlert = class(TJvCustomFormDesktopAlert)
-  private
-    FClickableMessage: Boolean;
-  protected
-    procedure InternalDoShow; override;
-    procedure DoDropDownClose(Sender: TObject);
-    procedure DoDropDownMenu(Sender: TObject; MousePos: TPoint; var Handled: Boolean);
-  public
-    imIcon: TImage;
-    lblText: TJvLabel;
-    lblHeader: TLabel;
-    tbDropDown: TJvDesktopAlertButton;
-    tbClose: TJvDesktopAlertButton;
-  public
-    constructor Create(AOwner: TComponent); override;
-    procedure DoButtonClick(Sender: TObject);
-
-    property ClickableMessage: Boolean read FClickableMessage write FClickableMessage;
     property ParentFont;
     property PopupMenu;
     property OnClose;
-    property OnShowing;
+    property OnShowing: TNotifyEvent read FOnShowing write FOnShowing;
     property OnShow;
-    property OnShown;
+    property OnShown: TNotifyEvent read FOnShown write FOnShown;
   end;
 
 {$IFDEF UNITVERSIONING}
@@ -324,8 +308,79 @@
   tbDropDown.OnDropDownClose := DoDropDownClose;
 end;
 
-procedure TJvFormDesktopAlert.InternalDoShow;
+
+procedure TJvFormDesktopAlert.FormPaint(Sender: TObject);
+begin
+  DrawDesktopAlertWindow(Canvas, ClientRect, FrameColor, WindowColorFrom, WindowColorTo, CaptionColorFrom, CaptionColorTo, Moveable or MoveAnywhere);
+end;
+
+{$IFDEF VCL}
+procedure TJvFormDesktopAlert.WMNCHitTest(var Msg: TWMNCHitTest);
+var
+  P: TPoint;
+begin
+  with Msg do
+    P := ScreenToClient(Point(XPos, YPos));
+  if ((P.Y <= cCaptionHeight) and Moveable) or (MoveAnywhere and (ControlAtPos(P, False) = nil)) then
+  begin
+    TJvDesktopAlert(Owner).StyleHandler.AbortAnimation;
+    Msg.Result := HTCAPTION;
+  end
+  else
+    inherited;
+end;
+
+procedure TJvFormDesktopAlert.WMActivate(var Message: TWMActivate);
 begin
+  if (Message.Active = WA_INACTIVE) or AllowFocus then
+    inherited
+  else
+    Message.Result := 1;
+end;
+
+{$ENDIF VCL}
+
+procedure TJvFormDesktopAlert.acCloseExecute(Sender: TObject);
+begin
+  if Closeable then
+    Close;
+end;
+
+procedure TJvFormDesktopAlert.MouseEnter(AControl: TControl);
+begin
+  inherited MouseEnter(AControl);
+  FMouseInControl := True;
+  //  SetFocus;
+  TJvDesktopAlert(Owner).StyleHandler.AbortAnimation;
+  if Assigned(FOnMouseEnter) then
+    FOnMouseEnter(Self);
+end;
+
+procedure TJvFormDesktopAlert.MouseLeave(AControl: TControl);
+var
+  P: TPoint;
+begin
+  inherited MouseLeave(AControl);
+  // make sure the mouse actually left the outer boundaries
+  GetCursorPos(P);
+  if MouseInControl and not PtInRect(BoundsRect, P) then
+  begin
+    if Assigned(FOnMouseLeave) then
+      FOnMouseLeave(Self);
+    if not TJvDesktopAlert(Owner).StyleHandler.Active
+        and (TJvDesktopAlert(Owner).StyleHandler.DisplayDuration > 0) then
+      TJvDesktopAlert(Owner).StyleHandler.DoEndAnimation;
+    FMouseInControl := False;
+  end;
+end;
+
+procedure TJvFormDesktopAlert.DoShow;
+begin
+  if Assigned(OnShowing) then
+    OnShowing(Self);
+    
+  inherited DoShow;
+  TJvDesktopAlert(Owner).StyleHandler.AbortAnimation;
   lblText.HotTrackFont.Style := [fsUnderLine];
   lblText.HotTrackFont.Color := clNavy;
   if ClickableMessage then
@@ -343,7 +398,7 @@
     tbDropDown.Visible := False;
 
   // if the form is not closeable, then do not show the button
-  if not Closeable then
+  if not Closeable then 
   begin
     tbClose.Visible := False;
     tbDropDown.Left := tbClose.Left;
@@ -355,6 +410,75 @@
   lblText.Left := lblHeader.Left + 8;
   lblText.Width := tbDropDown.Left - lblText.Left;
   lblText.Top := lblHeader.Top + lblHeader.Height;
+  TJvDesktopAlert(Owner).StyleHandler.DoStartAnimation;
+  MouseTimer.Enabled := True;
+
+  if Assigned(OnShown) then
+    OnShown(Self);
+end;
+
+{$IFDEF VCL}
+procedure TJvFormDesktopAlert.WMMove(var Msg: TWMMove);
+begin
+  inherited;
+  if Showing and Assigned(FOnUserMove) then
+    FOnUserMove(Self);
+end;
+{$ENDIF VCL}
+
+procedure TJvFormDesktopAlert.SetNewTop(const Value: Integer);
+begin
+  SetNewOrigin(Left, Value);
+end;
+
+procedure TJvFormDesktopAlert.SetNewLeft(const Value: Integer);
+begin
+  SetNewOrigin(Value, Top);
+end;
+
+procedure TJvFormDesktopAlert.SetNewOrigin(ALeft, ATop: Integer);
+var
+  MoveEvent: TNotifyEvent;
+begin
+  if ((Top <> ATop) or (Left <> ALeft)) and not MouseInControl then
+  begin
+    MoveEvent := FOnUserMove;
+    FOnUserMove := nil;
+    Left := ALeft;
+    Top := ATop;
+    FOnUserMove := MoveEvent;
+  end;
+end;
+
+procedure TJvFormDesktopAlert.DoMouseTimer(Sender: TObject);
+var
+  P: TPoint;
+
+  function IsInForm(P: TPoint): Boolean;
+  var
+    W: TControl;
+  begin
+    W := ControlAtPos(P, True, True);
+    Result := (W = Self) or (FindVCLWindow(P) = Self) or ((W <> nil) and (GetParentForm(W) = Self));
+  end;
+
+begin
+  // this is here to ensure that MouseInControl is correctly set even
+  // if we never got a CM_MouseLeave (that happens a lot)
+  MouseTimer.Enabled := False;
+  GetCursorPos(P);
+  FMouseInControl := PtInRect(BoundsRect, P); // and IsInForm(P);
+  MouseTimer.Enabled := True;
+  if not TJvDesktopAlert(Owner).StyleHandler.Active and not MouseInControl and (TJvDesktopAlert(Owner).StyleHandler.DisplayDuration > 0) then
+    TJvDesktopAlert(Owner).StyleHandler.DoEndAnimation;
+end;
+
+procedure TJvFormDesktopAlert.DoClose(var Action: TCloseAction);
+begin
+  MouseTimer.Enabled := False;
+  inherited DoClose(Action);
+  if Action = caHide then
+    ShowWindow(Handle, SW_HIDE);
 end;
 
 //=== { TJvDesktopAlertButton } ==============================================
@@ -568,6 +692,16 @@
   end;
 end;
 
+procedure TJvFormDesktopAlert.JvDeskTopAlertAutoFree(var Msg: TMessage);
+begin
+  // WParam is us, LParam is the TJvDesktopAlert
+  if Msg.WParam = WPARAM(Self) then
+  begin
+    Release;
+    TObject(Msg.LParam).Free;
+  end;
+end;
+
 procedure TJvFormDesktopAlert.DoButtonClick(Sender: TObject);
 var
   FEndInterval: Cardinal;
@@ -607,162 +741,16 @@
   TJvDesktopAlert(Owner).StyleHandler.EndInterval := 0;
 end;
 
-{ TJvCustomFormDesktopAlert }
-
-procedure TJvCustomFormDesktopAlert.acCloseExecute(Sender: TObject);
-begin
-  if Closeable then
-    Close;
-end;
-
-constructor TJvCustomFormDesktopAlert.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-
-  MouseTimer := TTimer.Create(Self);
-  MouseTimer.Enabled := False;
-  MouseTimer.Interval := 200;
-  MouseTimer.OnTimer := DoMouseTimer;
-  MouseTimer.Enabled := True;
-
-  BorderStyle := fbsNone;
-  BorderIcons := [];
-  Scaled := False;
-  OnPaint := FormPaint;
-
-  acClose := TAction.Create(Self);
-  acClose.Caption := RsClose;
-
-  acClose.ShortCut := ShortCut(VK_F4, [ssAlt]); // 32883
-  acClose.OnExecute := acCloseExecute;
-end;
-
-procedure TJvCustomFormDesktopAlert.DoClose(var Action: TCloseAction);
-begin
-  MouseTimer.Enabled := False;
-  inherited DoClose(Action);
-  if Action = caHide then
-    ShowWindow(Handle, SW_HIDE);
-end;
-
-procedure TJvCustomFormDesktopAlert.DoMouseTimer(Sender: TObject);
-var
-  P: TPoint;
-
-  function IsInForm(P: TPoint): Boolean;
-  var
-    W: TControl;
-  begin
-    W := ControlAtPos(P, True, True);
-    Result := (W = Self) or (FindVCLWindow(P) = Self) or ((W <> nil) and (GetParentForm(W) = Self));
-  end;
-
-begin
-  // this is here to ensure that MouseInControl is correctly set even
-  // if we never got a CM_MouseLeave (that happens a lot)
-  MouseTimer.Enabled := False;
-  GetCursorPos(P);
-  FMouseInControl := PtInRect(BoundsRect, P); // and IsInForm(P);
-  MouseTimer.Enabled := True;
-  if not TJvCustomDesktopAlert(Owner).StyleHandler.Active and not MouseInControl and (TJvCustomDesktopAlert(Owner).StyleHandler.DisplayDuration > 0) then
-    TJvCustomDesktopAlert(Owner).StyleHandler.DoEndAnimation;
-end;
-
-procedure TJvCustomFormDesktopAlert.DoShow;
-begin
-  if Assigned(OnShowing) then
-    OnShowing(Self);
-
-  inherited DoShow;
-  TJvCustomDesktopAlert(Owner).StyleHandler.AbortAnimation;
-  InternalDoShow;
-  TJvCustomDesktopAlert(Owner).StyleHandler.DoStartAnimation;
-  MouseTimer.Enabled := True;
-
-  if Assigned(OnShown) then
-    OnShown(Self);
-end;
-
-procedure TJvCustomFormDesktopAlert.FormPaint(Sender: TObject);
-begin
-  DrawDesktopAlertWindow(Canvas, ClientRect, FrameColor, WindowColorFrom, WindowColorTo, CaptionColorFrom, CaptionColorTo, Moveable or MoveAnywhere);
-end;
-
-function TJvCustomFormDesktopAlert.GetVisible: Boolean;
+procedure TJvFormDesktopAlert.WMMouseActivate(var Message: TWMMouseActivate);
 begin
-  Result := IsWindowVisible(Handle);
-end;
-
-procedure TJvCustomFormDesktopAlert.InternalDoShow;
-begin
-//
-end;
-
-procedure TJvCustomFormDesktopAlert.JvDeskTopAlertAutoFree(var Msg: TMessage);
-begin
-  // WParam is us, LParam is the TJvDesktopAlert
-  if Msg.WParam = WPARAM(Self) then
-  begin
-    Release;
-    TObject(Msg.LParam).Free;
-  end;
-end;
-
-procedure TJvCustomFormDesktopAlert.MouseEnter(AControl: TControl);
-begin
-  inherited MouseEnter(AControl);
-  FMouseInControl := True;
-  //  SetFocus;
-  TJvCustomDesktopAlert(Owner).StyleHandler.AbortAnimation;
-  if Assigned(FOnMouseEnter) then
-    FOnMouseEnter(Self);
-end;
-
-procedure TJvCustomFormDesktopAlert.MouseLeave(AControl: TControl);
-var
-  P: TPoint;
-begin
-  inherited MouseLeave(AControl);
-  // make sure the mouse actually left the outer boundaries
-  GetCursorPos(P);
-  if MouseInControl and not PtInRect(BoundsRect, P) then
-  begin
-    if Assigned(FOnMouseLeave) then
-      FOnMouseLeave(Self);
-    if not TJvCustomDesktopAlert(Owner).StyleHandler.Active
-        and (TJvCustomDesktopAlert(Owner).StyleHandler.DisplayDuration > 0) then
-      TJvCustomDesktopAlert(Owner).StyleHandler.DoEndAnimation;
-    FMouseInControl := False;
-  end;
-end;
-
-procedure TJvCustomFormDesktopAlert.SetNewLeft(const Value: Integer);
-begin
-  SetNewOrigin(Value, Top);
-end;
-
-procedure TJvCustomFormDesktopAlert.SetNewOrigin(ALeft, ATop: Integer);
-var
-  MoveEvent: TNotifyEvent;
-begin
-  if ((Top <> ATop) or (Left <> ALeft)) and not MouseInControl then
-  begin
-    MoveEvent := FOnUserMove;
-    FOnUserMove := nil;
-    Left := ALeft;
-    Top := ATop;
-    FOnUserMove := MoveEvent;
-  end;
-end;
-
-procedure TJvCustomFormDesktopAlert.SetNewTop(const Value: Integer);
-begin
-  SetNewOrigin(Left, Value);
+  if AllowFocus then
+    inherited
+  else
+    Message.Result := MA_NOACTIVATE;
 end;
 
-procedure TJvCustomFormDesktopAlert.ShowNoActivate;
+procedure TJvFormDesktopAlert.ShowNoActivate;
 begin
-  Visible := True;
   Include(FFormState, fsShowing);
 //  Windows.SetParent(Handle, 0);
 //-- The above was introduced to partially solve the issue of the visible
@@ -778,45 +766,10 @@
   Include(FFormState, fsVisible);
 end;
 
-{$IFDEF VCL}
-procedure TJvCustomFormDesktopAlert.WMActivate(var Message: TWMActivate);
+function TJvFormDesktopAlert.GetVisible: Boolean;
 begin
-  if (Message.Active = WA_INACTIVE) or AllowFocus then
-    inherited
-  else
-    Message.Result := 1;
-end;
-
-procedure TJvCustomFormDesktopAlert.WMMouseActivate(var Message: TWMMouseActivate);
-begin
-  if AllowFocus then
-    inherited
-  else
-    Message.Result := MA_NOACTIVATE;
-end;
-
-procedure TJvCustomFormDesktopAlert.WMMove(var Msg: TWMMove);
-begin
-  inherited;
-  if Showing and Assigned(FOnUserMove) then
-    FOnUserMove(Self);
-end;
-
-procedure TJvCustomFormDesktopAlert.WMNCHitTest(var Msg: TWMNCHitTest);
-var
-  P: TPoint;
-begin
-  with Msg do
-    P := ScreenToClient(Point(XPos, YPos));
-  if ((P.Y <= cCaptionHeight) and Moveable) or (MoveAnywhere and (ControlAtPos(P, False) = nil)) then
-  begin
-    TJvCustomDesktopAlert(Owner).StyleHandler.AbortAnimation;
-    Msg.Result := HTCAPTION;
-  end
-  else
-    inherited;
+  Result := IsWindowVisible(Handle);
 end;
-{$ENDIF VCL}
 
 initialization
   {$IFDEF UNITVERSIONING}
JvDesktopAlertForm.diff (16,027 bytes)

obones

2006-11-01 06:55

administrator   ~0010403

Why did TJvCustomFormDesktopAlert disappeared?
And why do you want it to be installed as a component? It's just a base for others to use, and base forms are never installed as a component.

mvrhov

2006-11-01 07:03

reporter   ~0010404

Last edited: 2006-11-01 07:07

I meant for TJvDesktopAlertForm to be registred as a component.
And it seems that patches are invalid, Why don't you upgrade from my full modified files. It should be easer.

2006-11-01 07:06

 

full source.zip (17,153 bytes)

obones

2007-06-19 03:10

administrator   ~0013397

This is now in SVN.

Issue History

Date Modified Username Field Change
2006-10-22 14:31 mvrhov New Issue
2006-10-22 14:32 mvrhov File Added: JvDesktopAlert.diff
2006-10-22 14:32 mvrhov File Added: JvDesktopAlertForm.diff
2006-11-01 06:55 obones Note Added: 0010403
2006-11-01 06:55 obones Status new => feedback
2006-11-01 07:03 mvrhov Note Added: 0010404
2006-11-01 07:06 mvrhov File Added: full source.zip
2006-11-01 07:07 mvrhov Note Edited: 0010404
2007-06-19 03:10 obones Status feedback => resolved
2007-06-19 03:10 obones Fixed in Version => Daily / SVN
2007-06-19 03:10 obones Resolution open => fixed
2007-06-19 03:10 obones Assigned To => obones
2007-06-19 03:10 obones Note Added: 0013397