Componentes.Terceros.jvcl/official/3.36/run/JvDockSupportProc.pas
2009-02-27 12:23:32 +00:00

530 lines
15 KiB
ObjectPascal

{-----------------------------------------------------------------------------
The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/MPL-1.1.html
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
the specific language governing rights and limitations under the License.
The Original Code is: JvDockSupportProc.pas, released on 2003-12-31.
The Initial Developer of the Original Code is luxiaoban.
Portions created by luxiaoban are Copyright (C) 2002,2003 luxiaoban.
All Rights Reserved.
Contributor(s):
You may retrieve the latest version of this file at the Project JEDI's JVCL home page,
located at http://jvcl.sourceforge.net
Known Issues:
-----------------------------------------------------------------------------}
// $Id: JvDockSupportProc.pas 11059 2006-11-29 17:12:58Z marquardt $
unit JvDockSupportProc;
{$I jvcl.inc}
interface
uses
{$IFDEF USEJVCL}
{$IFDEF UNITVERSIONING}
JclUnitVersioning,
{$ENDIF UNITVERSIONING}
{$ENDIF USEJVCL}
Windows, Messages, Classes, Graphics, Controls, Forms;
type
TJvDockListScanKind = (lskForward, lskBackward);
function JvDockStreamDataToString(Stream: TStream): string;
procedure JvDockStringToStreamData(Stream: TStream; const Data: string);
function JvDockFindDockFormWithName(const FormName: string;
FromDockManager: Boolean = False;
FromList: Boolean = True;
ScanKind: TJvDockListScanKind = lskForward): TCustomForm;
function JvDockFindDockServerFormWithName(const FormName: string;
FromDockManager: Boolean = False;
FromList: Boolean = True;
ScanKind: TJvDockListScanKind = lskForward): TCustomForm;
function JvDockFindDockClientFormWithName(const FormName: string;
FromDockManager: Boolean = False;
FromList: Boolean = True;
ScanKind: TJvDockListScanKind = lskForward): TCustomForm;
function JvDockFindDockServerFromDockManager(const FormName: string;
FromList: Boolean = True;
ScanKind: TJvDockListScanKind = lskForward): TCustomForm;
function JvDockFindDockClientFromDockManager(const FormName: string;
FromList: Boolean = True;
ScanKind: TJvDockListScanKind = lskForward): TCustomForm;
function JvDockFindDockFormFromScreen(const FormName: string;
ScanKind: TJvDockListScanKind = lskForward): TCustomForm;
function JvDockGetMinOffset(TBDockSize, ControlSize: Integer; Scale: Real): Integer;
function JvDockGetNoNClientMetrics: TNONCLIENTMETRICS;
function JvDockGetSysCaptionHeight: Integer;
function JvDockGetSysBorderWidth: Integer;
function JvDockGetSysCaptionHeightAndBorderWidth: Integer;
function JvDockGetActiveTitleBeginColor: TColor;
function JvDockGetActiveTitleEndColor: TColor;
function JvDockGetInactiveTitleBeginColor: TColor;
function JvDockGetInactiveTitleEndColor: TColor;
function JvDockGetTitleFontColor(Active: Boolean): TColor;
function JvDockGetActiveTitleFontColor: TColor;
function JvDockGetInactiveTitleFontColor: TColor;
function JvDockGetTitleFont: TFont;
procedure JvDockLockWindow(Control: TWinControl);
procedure JvDockUnLockWindow;
function JvDockCreateNCMessage(Control: TControl; Msg: Cardinal; HTFlag: Integer; Pos: TPoint): TWMNCHitMessage;
function JvDockExchangeOrient(Orient: TDockOrientation): TDockOrientation;
function JvDockGetControlOrient(AControl: TControl): TDockOrientation;
function JvDockGetControlSize(AControl: TControl): Integer;
procedure RegisterSettingChangeClient(Client: TObject; Event: TNotifyEvent);
procedure UnRegisterSettingChangeClient(Client: TObject);
{$IFDEF USEJVCL}
{$IFDEF UNITVERSIONING}
const
UnitVersioning: TUnitVersionInfo = (
RCSfile: '$URL: https://jvcl.svn.sourceforge.net/svnroot/jvcl/branches/JVCL3_36_PREPARATION/run/JvDockSupportProc.pas $';
Revision: '$Revision: 11059 $';
Date: '$Date: 2006-11-29 18:12:58 +0100 (mer., 29 nov. 2006) $';
LogPath: 'JVCL\run'
);
{$ENDIF UNITVERSIONING}
{$ENDIF USEJVCL}
implementation
uses
SysUtils, Math,
{$IFDEF USEJVCL}
JvJVCLUtils,
{$ENDIF USEJVCL}
JvDockControlForm, JvDockGlobals;
type
{ The dock style components used to hook the form they were dropped on, so
they could respond to Windows setting changes. The components can now use
the TJvMsgWindow -via the RegisterSettingChangeClient procedure- that creates
a window so it is able to receive WM_SETTINGCHANGE messages. Notification is
done via the Observer pattern
}
TJvMsgWindow = class(TObject)
private
FHandle: HWND;
FClients: TList;
FNotifyEvents: TList;
procedure WndProc(var Msg: TMessage);
procedure NotifyClients;
public
constructor Create; virtual;
destructor Destroy; override;
procedure RegisterClient(Client: TObject; Event: TNotifyEvent); virtual;
procedure UnRegisterClient(Client: TObject); virtual;
end;
var
GMsgHook: TJvMsgWindow;
JvDockTitleFont: TFont = nil;
function JvDockStreamDataToString(Stream: TStream): string;
var
Ch: Char;
begin
Result := '';
Stream.Position := 0;
while Stream.Position < Stream.Size do
begin
Stream.Read(Ch, SizeOf(Ch));
Result := Result + IntToHex(Ord(Ch), 2);
end;
end;
procedure JvDockStringToStreamData(Stream: TStream; const Data: string);
var
I: Integer;
Ch: Char;
begin
I := 1;
while I < Length(Data) do
begin
Ch := Char(StrToInt('$' + Copy(Data, I, 2)));
Stream.Write(Ch, SizeOf(Ch));
Inc(I, 2);
end;
end;
function JvDockFindDockFormWithName(const FormName: string; FromDockManager: Boolean;
FromList: Boolean; ScanKind: TJvDockListScanKind): TCustomForm;
begin
Result := JvDockFindDockClientFormWithName(FormName, FromDockManager, FromList, ScanKind);
if Result = nil then
Result := JvDockFindDockServerFormWithName(FormName, FromDockManager, FromList, ScanKind);
end;
function JvDockFindDockServerFormWithName(const FormName: string; FromDockManager: Boolean;
FromList: Boolean; ScanKind: TJvDockListScanKind): TCustomForm;
begin
if FromDockManager then
Result := JvDockFindDockServerFromDockManager(FormName, FromList, ScanKind)
else
Result := JvDockFindDockFormFromScreen(FormName, ScanKind);
end;
function JvDockFindDockClientFormWithName(const FormName: string; FromDockManager: Boolean;
FromList: Boolean; ScanKind: TJvDockListScanKind): TCustomForm;
begin
if FromDockManager then
Result := JvDockFindDockClientFromDockManager(FormName, FromList, ScanKind)
else
Result := JvDockFindDockFormFromScreen(FormName, ScanKind);
end;
function JvDockFindDockServerFromDockManager(const FormName: string; FromList: Boolean;
ScanKind: TJvDockListScanKind): TCustomForm;
var
I: Integer;
begin
case ScanKind of
lskForward:
for I := 0 to JvGlobalDockManager.DockServerCount - 1 do
begin
Result := JvGlobalDockManager.DockServer[I].ParentForm;
if Assigned(Result) and (FormName = Result.Name) then
Exit;
end;
lskBackward:
for I := JvGlobalDockManager.DockServerCount - 1 downto 0 do
begin
Result := JvGlobalDockManager.DockServer[I].ParentForm;
if Assigned(Result) and (FormName = Result.Name) then
Exit;
end;
end;
Result := nil;
end;
function JvDockFindDockClientFromDockManager(const FormName: string; FromList: Boolean;
ScanKind: TJvDockListScanKind): TCustomForm;
var
I: Integer;
begin
case ScanKind of
lskForward:
for I := 0 to JvGlobalDockManager.DockClientCount - 1 do
begin
Result := JvGlobalDockManager.DockClient[I].ParentForm;
if Assigned(Result) and (FormName = Result.Name) then
Exit;
end;
lskBackward:
for I := JvGlobalDockManager.DockClientCount - 1 downto 0 do
begin
Result := JvGlobalDockManager.DockClient[I].ParentForm;
if Assigned(Result) and (FormName = Result.Name) then
Exit;
end;
end;
Result := nil;
end;
function JvDockFindDockFormFromScreen(const FormName: string;
ScanKind: TJvDockListScanKind): TCustomForm;
var
I: Integer;
begin
Result := nil;
case ScanKind of
lskForward:
for I := 0 to Screen.CustomFormCount - 1 do
if FormName = Screen.CustomForms[I].Name then
begin
Result := Screen.CustomForms[I];
Break;
end;
lskBackward:
for I := Screen.CustomFormCount - 1 downto 0 do
if FormName = Screen.CustomForms[I].Name then
begin
Result := Screen.CustomForms[I];
Break;
end;
end;
end;
function JvDockGetMinOffset(TBDockSize, ControlSize: Integer; Scale: Real): Integer;
begin
if (Scale < 0) or (Scale > 1) then
Scale := 1;
Result := Min(TBDockSize, Round(ControlSize * Scale));
end;
function JvDockGetNoNClientMetrics: TNONCLIENTMETRICS;
begin
Result.cbSize := SizeOf(TNONCLIENTMETRICS);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, Result.cbSize,
@Result, 0);
end;
function JvDockGetSysCaptionHeight: Integer;
begin
Result := JvDockGetNoNClientMetrics.iCaptionHeight
end;
function JvDockGetSysBorderWidth: Integer;
begin
Result := JvDockGetNoNClientMetrics.iBorderWidth;
end;
function JvDockGetSysCaptionHeightAndBorderWidth: Integer;
var
NoNCM: TNONCLIENTMETRICS;
begin
NoNCM := JvDockGetNoNClientMetrics;
Result := NoNCM.iBorderWidth + NoNCM.iCaptionHeight;
end;
function JvDockGetActiveTitleBeginColor: TColor;
begin
Result := GetSysColor(COLOR_ACTIVECAPTION);
end;
function JvDockGetActiveTitleEndColor: TColor;
begin
Result := GetSysColor(COLOR_GRADIENTACTIVECAPTION);
end;
function JvDockGetInactiveTitleBeginColor: TColor;
begin
Result := GetSysColor(COLOR_INACTIVECAPTION);
end;
function JvDockGetInactiveTitleEndColor: TColor;
begin
Result := GetSysColor(COLOR_GRADIENTINACTIVECAPTION);
end;
function JvDockGetTitleFontColor(Active: Boolean): TColor;
begin
if Active then
Result := JvDockGetActiveTitleFontColor
else
Result := JvDockGetInactiveTitleFontColor;
end;
function JvDockGetActiveTitleFontColor: TColor;
begin
Result := GetSysColor(COLOR_CAPTIONTEXT);
end;
function JvDockGetInactiveTitleFontColor: TColor;
begin
Result := GetSysColor(COLOR_INACTIVECAPTIONTEXT);
end;
function JvDockGetTitleFont: TFont;
var
NoNCM: TNONCLIENTMETRICS;
begin
if JvDockTitleFont = nil then
JvDockTitleFont := TFont.Create;
Result := JvDockTitleFont;
NoNCM := JvDockGetNoNClientMetrics;
Result.Handle := CreateFontIndirect(NoNCM.lfCaptionFont);
end;
var
GLockCount: Integer;
GWindowLocked: Boolean;
procedure JvDockLockWindow(Control: TWinControl);
begin
{ Ignore Control parameter; otherwise nested JvDockLockWindow calls are not possible }
if GLockCount = 0 then
GWindowLocked := LockWindowUpdate(GetDesktopWindow);
Inc(GLockCount);
end;
procedure JvDockUnLockWindow;
begin
Dec(GLockCount);
if GLockCount = 0 then
begin
if GWindowLocked then
LockWindowUpdate(0);
GWindowLocked := False;
end;
end;
function JvDockCreateNCMessage(Control: TControl; Msg: Cardinal; HTFlag: Integer;
Pos: TPoint): TWMNCHitMessage;
begin
Result.Msg := Msg;
Result.HitTest := HTFlag;
Pos := Control.ClientToScreen(Pos);
Result.XCursor := Pos.X;
Result.YCursor := Pos.Y;
end;
function JvDockExchangeOrient(Orient: TDockOrientation): TDockOrientation;
begin
case Orient of
doHorizontal:
Result := doVertical;
doVertical:
Result := doHorizontal;
else
Result := doNoOrient;
end;
end;
function JvDockGetControlOrient(AControl: TControl): TDockOrientation;
begin
Assert(AControl <> nil);
Result := doNoOrient;
case AControl.Align of
alClient, alNone:
Result := doNoOrient;
alLeft, alRight:
Result := doVertical;
alTop, alBottom:
Result := doHorizontal;
end;
end;
function JvDockGetControlSize(AControl: TControl): Integer;
begin
case JvDockGetControlOrient(AControl) of
doVertical:
Result := AControl.Width;
doHorizontal:
Result := AControl.Height;
else
raise Exception.CreateRes(@RsEDockCannotGetValueWithNoOrient);
end;
end;
procedure RegisterSettingChangeClient(Client: TObject; Event: TNotifyEvent);
begin
if GMsgHook = nil then
GMsgHook := TJvMsgWindow.Create;
GMsgHook.RegisterClient(Client, Event);
end;
procedure UnRegisterSettingChangeClient(Client: TObject);
begin
if Assigned(GMsgHook) then
begin
GMsgHook.UnRegisterClient(Client);
if GMsgHook.FClients.Count = 0 then
FreeAndNil(GMsgHook);
end;
end;
//=== { TJvMsgWindow } =======================================================
constructor TJvMsgWindow.Create;
begin
inherited Create;
FClients := TList.Create;
FNotifyEvents := TList.Create;
{$IFDEF USEJVCL}
FHandle := AllocateHWndEx(WndProc);
{$ELSE}
FHandle := AllocateHWnd(WndProc);
{$ENDIF USEJVCL}
end;
destructor TJvMsgWindow.Destroy;
begin
if FHandle <> 0 then
{$IFDEF USEJVCL}
DeallocateHWndEx(FHandle);
{$ELSE}
DeallocateHWnd(FHandle);
{$ENDIF USEJVCL}
FClients.Free;
FNotifyEvents.Free;
inherited Destroy;
end;
procedure TJvMsgWindow.NotifyClients;
var
I: Integer;
NotifyEvent: TNotifyEvent;
begin
for I := 0 to FClients.Count - 1 do
begin
TMethod(NotifyEvent).Code := FNotifyEvents[I];
TMethod(NotifyEvent).Data := FClients[I];
NotifyEvent(Self);
end;
end;
procedure TJvMsgWindow.RegisterClient(Client: TObject; Event: TNotifyEvent);
begin
FClients.Add(Client);
FNotifyEvents.Add(TMethod(Event).Code);
end;
procedure TJvMsgWindow.UnRegisterClient(Client: TObject);
var
Index: Integer;
begin
Index := FClients.IndexOf(Client);
if Index <> -1 then
begin
FClients.Delete(Index);
FNotifyEvents.Delete(Index);
end;
end;
procedure TJvMsgWindow.WndProc(var Msg: TMessage);
begin
with Msg do
if (Msg = WM_SETTINGCHANGE) or (Msg = WM_SYSCOLORCHANGE) then
try
NotifyClients;
except
{$IFDEF COMPILER6_UP}
if Assigned(ApplicationHandleException) then
ApplicationHandleException(Self);
{$ELSE}
Application.HandleException(Self);
{$ENDIF COMPILER6_UP}
end
else
{ !! Call DefWindowProc, so messages like WM_QUERYENDSESSION are
processed correctly, see Mantis #3527 }
Result := DefWindowProc(FHandle, Msg, wParam, lParam);
end;
initialization
{$IFDEF USEJVCL}
{$IFDEF UNITVERSIONING}
RegisterUnitVersion(HInstance, UnitVersioning);
{$ENDIF UNITVERSIONING}
{$ENDIF USEJVCL}
finalization
FreeAndNil(JvDockTitleFont);
FreeAndNil(GMsgHook);
{$IFDEF USEJVCL}
{$IFDEF UNITVERSIONING}
UnregisterUnitVersion(HInstance);
{$ENDIF UNITVERSIONING}
{$ENDIF USEJVCL}
end.