//////////////////////////////////////////////////////////////////////////////// // All code below is exclusively owned by author of Chess4Net - Pavel Perminov // (packpaul@mail.ru, packpaul1@gmail.com). // Any changes, modifications, borrowing and adaptation are a subject for // explicit permition from the owner. unit ModalForm; interface uses Forms, TntForms, Dialogs, Classes, Windows, Controls; type TModalForm = class; TModalFormClass = class of TModalForm; TModalFormID = (mfNone, mfMsgClose, mfMsgLeave, mfMsgAbort, mfMsgResign, mfMsgDraw, mfMsgTakeBack, mfMsgAdjourn, mfConnecting, mfGameOptions, mfLookFeel, mfCanPause, mfContinue, mfIncompatible, mfDontShowDlg {$IFDEF SKYPE} , mfSelectSkypeContact {$ENDIF} {$IFDEF MIRANDA} , mfTransmitting, mfTransmitGame {$ENDIF} ); TModalFormHandler = procedure(modSender: TModalForm; modID: TModalFormID) of object; TDialogs = class private IDCount: array[TModalFormID] of word; frmList: TList; function GetShowing: boolean; protected RHandler: TModalFormHandler; public Owner: TForm; constructor Create(Owner: TForm; Handler: TModalFormHandler); destructor Destroy; override; procedure MessageDlg(const wstrMsg: WideString; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; msgDlgID: TModalFormID); function CreateDialog(modalFormClass: TModalFormClass): TModalForm; procedure SetShowing(msgDlg: TModalForm); procedure UnsetShowing(msgDlg: TModalForm); function InFormList(frm: TForm): boolean; procedure BringToFront; procedure MoveForms(dx, dy: integer); procedure CloseNoneDialogs; class procedure ShowMessage(const wstrMsg: WideString); class function HasStayOnTopOwners: boolean; property Showing: boolean read GetShowing; end; TModalForm = class(TTntForm) procedure FormShow(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure ButtonClick(Sender: TObject); private GenFormShow: TNotifyEvent; GenFormClose: TCloseEvent; protected RHandler: TModalFormHandler; dlgOwner: TDialogs; constructor Create(dlgOwner: TDialogs; modHandler: TModalFormHandler); reintroduce; overload; virtual; function GetHandle: hWnd; virtual; function GetEnabled_: boolean; virtual; procedure SetEnabled_(flag: boolean); virtual; function GetLeft_: integer; virtual; procedure SetLeft_(x: integer); virtual; function GetTop_: integer; virtual; procedure SetTop_(y: integer); virtual; function GetModalID: TModalFormID; virtual; function RGetModalResult: TModalResult; virtual; procedure RSetModalResult(Value: TModalResult); virtual; public constructor Create(Owner: TForm; modHandler: TModalFormHandler = nil); reintroduce; overload; virtual; procedure Show; virtual; procedure Close; virtual; property Handle: hWnd read GetHandle; property Enabled: boolean read GetEnabled_ write SetEnabled_; property Left: integer read GetLeft_ write SetLeft_; property Top: integer read GetTop_ write SetTop_; property ModalResult: TModalResult read RGetModalResult write RSetModalResult; end; implementation uses SysUtils, StdCtrls, DialogUnit, GlobalsUnit; var g_lstDialogs: TList = nil; //////////////////////////////////////////////////////////////////////////////// // TModalForm procedure TModalForm.FormShow(Sender: TObject); var frmOwner: TForm; selfForm: TForm; procedure NCorrectIfOutOfScreen(var iLeft, iTop: integer); var R: TRect; M: TMonitor; begin if (Assigned(frmOwner)) then begin M := Screen.MonitorFromRect(frmOwner.BoundsRect); R := M.WorkareaRect; end else R := Screen.WorkAreaRect; if ((iLeft + selfForm.Width) > R.Right) then iLeft := R.Right - selfForm.Width; if (iLeft < R.Left) then iLeft := R.Left; if ((iTop + selfForm.Height) > R.Bottom) then iTop := R.Bottom - selfForm.Height; if (iTop < R.Top) then iTop := R.Top; end; var iWidth, iHeight: integer; iLeft, iTop: integer; begin // TModalForm.FormShow selfForm := Sender as TForm; frmOwner := nil; if (Assigned(Owner)) then begin frmOwner := (Owner as TForm); iLeft := frmOwner.Left; iTop := frmOwner.Top; iWidth := frmOwner.Width; iHeight := frmOwner.Height; end else begin iLeft := 0; iTop := 0; iWidth := Screen.Width; iHeight := Screen.Height; end; iLeft := iLeft + (iWidth - selfForm.Width) div 2; iTop := iTop + (iHeight - selfForm.Height) div 2; NCorrectIfOutOfScreen(iLeft, iTop); selfForm.Left := iLeft; selfForm.Top := iTop; if (Assigned(GenFormShow)) then GenFormShow(Sender); end; procedure TModalForm.FormClose(Sender: TObject; var Action: TCloseAction); begin if Assigned(GenFormClose) then GenFormClose(Sender, Action); if Assigned(dlgOwner) then dlgOwner.UnsetShowing(self); if fsModal in FormState then exit; if (Assigned(RHandler)) then RHandler(self, GetModalID); Action := caFree; end; procedure TModalForm.ButtonClick(Sender: TObject); begin if (fsModal in FormState) then exit; Close; end; constructor TModalForm.Create(Owner: TForm; modHandler: TModalFormHandler); var i: integer; begin if (Assigned(Owner)) then FormStyle := Owner.FormStyle; inherited Create(Owner); RHandler := modHandler; GenFormShow := OnShow; GenFormClose := OnClose; OnShow := FormShow; OnClose := FormClose; for i := 0 to (ComponentCount - 1) do begin if (Components[i] is TButton) then (Components[i] as TButton).OnClick := ButtonClick; end; end; constructor TModalForm.Create(dlgOwner: TDialogs; modHandler: TModalFormHandler); begin self.dlgOwner := dlgOwner; Create(dlgOwner.Owner, modHandler); dlgOwner.SetShowing(self); end; function TModalForm.GetModalID : TModalFormID; begin Result := mfNone; end; function TModalForm.GetHandle: hWnd; begin Result := inherited Handle; end; function TModalForm.GetEnabled_: boolean; begin Result := inherited Enabled; end; procedure TModalForm.SetEnabled_(flag: boolean); begin inherited Enabled := flag; end; procedure TModalForm.Show; begin inherited Show; end; procedure TModalForm.Close; begin inherited Close; end; function TModalForm.GetLeft_: integer; begin Result := inherited Left; end; procedure TModalForm.SetLeft_(x: integer); begin inherited Left := x; end; function TModalForm.GetTop_: integer; begin Result := inherited Top; end; procedure TModalForm.SetTop_(y: integer); begin inherited Top := y; end; function TModalForm.RGetModalResult: TModalResult; begin Result := inherited ModalResult; end; procedure TModalForm.RSetModalResult(Value: TModalResult); begin inherited ModalResult := Value; end; //////////////////////////////////////////////////////////////////////////////// // TDialogs constructor TDialogs.Create(Owner: TForm; Handler: TModalFormHandler); var i: TModalFormID; begin inherited Create; self.Owner := Owner; self.RHandler := Handler; frmList := TList.Create; for i := Low(TModalFormID) to High(TModalFormID) do IDCount[i] := 0; if (not Assigned(g_lstDialogs)) then g_lstDialogs := TList.Create; g_lstDialogs.Add(self); end; destructor TDialogs.Destroy; var i: integer; ModalForm: TModalForm; begin if (Assigned(g_lstDialogs)) then begin g_lstDialogs.Remove(self); if (g_lstDialogs.Count = 0) then FreeAndNil(g_lstDialogs); end; for i := 0 to frmList.Count - 1 do begin ModalForm := frmList[i]; ModalForm.RHandler := nil; ModalForm.dlgOwner := nil; // ModalForm.Release; ModalForm.Free; end; inherited; end; function TDialogs.GetShowing: boolean; var i: TModalFormID; begin Result := TRUE; for i := Low(TModalFormID) to High(TModalFormID) do begin if IDCount[i] > 0 then exit; end; Result := FALSE; end; procedure TDialogs.UnsetShowing(msgDlg: TModalForm); var i: integer; begin dec(IDCount[msgDlg.GetModalID]); if (Assigned(msgDlg)) then begin for i := 0 to frmList.Count - 1 do begin if (TModalForm(frmList[i]).Handle = msgDlg.Handle) then begin frmList.Delete(i); break; end; end; // for end; if (frmList.Count > 0) then begin TModalForm(frmList.Last).Enabled := TRUE; TModalForm(frmList.Last).SetFocus; end else begin if (Assigned(Owner)) then begin Owner.Enabled := TRUE; Owner.SetFocus; end; end; end; function TDialogs.InFormList(frm: TForm): boolean; var i: integer; begin for i := 0 to frmList.Count - 1 do begin if TModalForm(frmList[i]).Handle = frm.Handle then begin Result := TRUE; exit; end; end; Result := FALSE; end; procedure TDialogs.MessageDlg(const wstrMsg: WideString; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; msgDlgID: TModalFormID); var DialogForm: TDialogForm; begin if ((msgDlgID <> mfNone) and (IDCount[msgDlgID] > 0)) then exit; DialogForm := TDialogForm.Create(self, wstrMsg, DlgType, Buttons, msgDlgID, RHandler, HasStayOnTopOwners); DialogForm.Caption := DIALOG_CAPTION; SetShowing(DialogForm); DialogForm.Show; frmList.Add(DialogForm); end; function TDialogs.CreateDialog(modalFormClass: TModalFormClass): TModalForm; begin Result := modalFormClass.Create(self, RHandler); frmList.Add(Result); end; procedure TDialogs.SetShowing(msgDlg: TModalForm); begin inc(IDCount[msgDlg.GetModalID]); if (frmList.Count > 0) then TModalForm(frmList.Last).Enabled := FALSE; end; procedure TDialogs.BringToFront; var i: integer; begin if frmList.Count = 0 then exit; for i := 0 to frmList.Count - 1 do TModalForm(frmList[i]).Show; TModalForm(frmList.Last).SetFocus; end; procedure TDialogs.MoveForms(dx, dy: integer); var i: integer; begin for i := 0 to frmList.Count - 1 do begin with TModalForm(frmList[i]) do begin Left := Left + dx; Top := Top + dy; end; end; end; procedure TDialogs.CloseNoneDialogs; var i: integer; Dlg: TModalForm; begin i := frmList.Count - 1; while (i >= 0) do begin Dlg := frmList[i]; if (Dlg.GetModalID = mfNone) then Dlg.Close; dec(i); end; end; class function TDialogs.HasStayOnTopOwners: boolean; var i: integer; Dlgs: TDialogs; begin Result := FALSE; if (not Assigned(g_lstDialogs)) then exit; for i := 0 to g_lstDialogs.Count - 1 do begin Dlgs := g_lstDialogs[i]; Result := (Assigned(Dlgs) and Assigned(Dlgs.Owner) and (Dlgs.Owner.FormStyle = fsStayOnTop)); if (Result) then exit; end; // for end; class procedure TDialogs.ShowMessage(const wstrMsg: WideString); var DummyOwner: TForm; DummyHandler: TModalFormHandler; begin DummyOwner := nil; DummyHandler := nil; with TDialogForm.Create(DummyOwner, wstrMsg, mtCustom, [mbOk], mfNone, DummyHandler, HasStayOnTopOwners) do try ShowModal; finally Release; end; end; end.