home *** CD-ROM | disk | FTP | other *** search
- unit Form3d;
-
- {
- TForm3D Class
- Copyright ⌐ 1995 Alan Ciemian All Rights Reserved
-
- The TForm3D class is a descendant of TForm that provides
- 3D borders for non-dialog forms. Also allows form sizing to be
- enabled/disabled.
-
- NOTES:
- - Requires that form have bsSizeable border style.
- - Sizing can be enabled/disabled with AllowResize property.
- - Handles all Title bar icon combinations.
- - Handles forms with or without menus(including multiline).
- - Handles all combinations of scroll bars.
- - NOT Designed/Tested for use as MDI Frame or MDI Child
-
- 05/01/95 - Initial Release
-
- 05/16/95 - Added FEnable3D field to store whether 3D drawing should be used
- or not depending on running Windows version.
- - Added check for iconic state before performing 3D drawing.
- - Modified caption drawing to left align caption if it is too wide
- for the available area, ala windows.
- }
-
-
- interface
-
- uses
- Messages, WinTypes,
- Classes, Controls, Forms;
-
-
- const
- CaptionH_STD = 20;
- MenuH_STD = 18;
-
-
- type
- TForm3D_NCPaintMode =
- (
- NCPaint_All,
- NCPaint_Activate,
- NCPaint_Deactivate
- );
-
- type
- TForm3D = class(TForm)
- private
- FEnable3D : Boolean; { Flag to identify if can use 3D effects }
- FSysMenuW : Integer; { Width of system menu, 0 if no sysmenu }
- FMinMaxW : Integer; { Width of min/max buttons, 0 if no min/max btns }
- FAllowResize : Boolean;
- { Private procedures }
- procedure NCPaint3D(const Mode: TForm3D_NCPaintMode);
- procedure ComputeNonClientDimensions;
- function ScrollBarVisible
- (
- const Code : Word; { SB_VERT or SB_HORZ }
- const WndRect : TRect
- ): Boolean;
- { Message Handlers }
- procedure WMNCHitTest (var Msg: TWMNCHitTest); message WM_NCHitTest;
- procedure WMNCPaint (var Msg: TWMNCPaint); message WM_NCPaint;
- procedure WMNCActivate(var Msg: TWMNCActivate); message WM_NCActivate;
- protected
- procedure CreateWnd; override;
- public
- constructor Create(AOwner: TComponent); override;
- { Properties }
- property AllowResize: Boolean
- read FAllowResize
- write FAllowResize
- default False;
- end;
-
-
- implementation
-
-
- uses
- WinProcs,
- SysUtils, Graphics,
- SysMet;
-
-
- function TForm3D.ScrollBarVisible
- (
- const Code : Word; { SB_VERT or SB_HORZ }
- const WndRect : TRect
- ): Boolean;
- var
- PtInScroll : TPoint;
- HVis : Boolean;
- begin
- Result := False;
-
- with WndRect, SysMetrics do
- begin
- { Determine if Horz scroll bar is visible. Need this for both horz and }
- { vert scroll bars. }
- { Two checks need to be satisfied, Style identifies scroll bar and }
- { windows recognizes HitTest in scroll bar. }
- { Hit Test check is required because there are cases when the window }
- { gets very small that windows decides not to draw the scroll bars }
- { even though they exist. }
- PtInScroll := Point(Left + Frame.cx + 1, Bottom - Frame.cy - 1);
- HVis := ( ((GetWindowLong(Handle, GWL_STYLE) and WS_HSCROLL) <> 0) and
- (Perform(WM_NCHITTEST, 0, LongInt(PtInScroll)) = HTHSCROLL) );
-
- if ( Code = SB_HORZ ) then
- begin { Done, return result computed above }
- Result := HVis;
- end
- else
- begin { Perform same procedure as above for vertical }
- PtInScroll := Point(Right - Frame.cx - 1, Bottom - Frame.cy - 1);
- if ( HVis ) then Dec(PtInScroll.y, HScrollBtn.cy);
- Result := ( ((GetWindowLong(Handle, GWL_STYLE) and WS_VSCROLL) <> 0) and
- (Perform(WM_NCHITTEST, 0, LongInt(PtInScroll)) = HTVSCROLL) );
- end;
- end;
- end;
-
-
-
- constructor TForm3D.Create
- (
- AOwner: TComponent
- );
- begin
- inherited Create(AOwner);
-
- { Set property defaults }
- FAllowResize := False;
- end;
-
-
- {
- CreateWnd is overriden so we can force certain properties before
- the window is created, and compute some parameters needed to
- do the 3D non-client drawing.
- }
- procedure TForm3D.CreateWnd;
- var
- AdjustHeight : Integer;
- Version : TWindowsVersion;
- VerMajor : Word;
- VerMinor : Word;
- begin
- { Border Style must be bsSizeable }
- BorderStyle := bsSizeable;
-
- { Compute height adjustments for font caption and menu. }
- { In large fonts video modes the client area would otherwise }
- { be reduced. }
- AdjustHeight := 0;
- with SysMetrics do
- begin
- Inc(AdjustHeight, CaptionH - CaptionH_STD);
- { Note: Only adjusts for a single line menu bar }
- if ( Menu <> nil ) then Inc(AdjustHeight, MenuH - MenuH_STD);
- end;
-
- { Let Form create }
- inherited CreateWnd;
-
- { Enforce the height adjustment }
- Height := Height + AdjustHeight;
-
- { 3D Drawing requires Win 3.x default behavior. }
- GetWindowsVersion(Version, VerMajor, VerMinor);
- FEnable3D := ( (VerMajor = 3) and (VerMinor = 10) );
-
- { Precompute dimensions of key non-client areas for later use }
- { in drawing the 3D effects. }
- if ( FEnable3D ) then ComputeNonClientDimensions;
- end;
-
-
- {
- ComputeNonClientDimensions precomputes some dimensions of non-client items
- to avoid doing it repeatedly during painting.
- }
- procedure TForm3D.ComputeNonClientDimensions;
-
- { We'd like to use the SM_CXSIZE system metrics value for the size of icons }
- { in the title bar but it is NOT correct for some video drivers/modes }
- function BitmapWidth(const BM_ID: Integer): Integer;
- var
- BM : THandle;
- BMInfo : WinTypes.TBitmap;
- begin
- BM := LoadBitmap(0, MakeIntResource(BM_ID));
- try
- GetObject(BM, SizeOf(BMInfo), @BMInfo);
- Result := BMInfo.bmWidth;
- finally
- DeleteObject(BM);
- end;
- end;
-
- begin
- FSysMenuW := 0;
- if ( biSystemMenu in BorderIcons ) then
- begin
- { Note: Close bitmap contains 2 bitmaps, app close and MDI child close }
- Inc(FSysMenuW, BitmapWidth(OBM_CLOSE) div 2);
- end;
-
- FMinMaxW := 0;
- if ( biMinimize in BorderIcons ) then
- begin
- Inc(FMinMaxW, BitmapWidth(OBM_REDUCE));
- end;
- if ( biMaximize in BorderIcons ) then
- begin
- Inc(FMinMaxW, BitmapWidth(OBM_ZOOM));
- end;
- end;
-
-
- {
- NCPaint3D handles the 3D specific painting for the form.
- }
- procedure TForm3D.NCPaint3D
- (
- const Mode: TForm3D_NCPaintMode
- );
- var
- WndRect : TRect;
- ClientRect : TRect;
- ClientH : Integer;
- ScrollH : Integer;
- DC : HDC;
- NCCanvas : TCanvas;
- Extra : Integer;
- CaptionRect : TRect;
- CaptionPt : TPoint;
- TM : TTextMetric;
- CaptionBuf : array[0..255] of Char;
- begin
- { Get window rect }
- WinProcs.GetWindowRect(Handle, WndRect);
- { Need to know if horz scroll bar present }
- ScrollH := 0;
- if ( ScrollBarVisible(SB_HORZ, WndRect) ) then
- begin
- ScrollH := SysMetrics.HScrollBtn.cy - 1;
- end;
- { Convert window rect to (0, 0) origin }
- with WndRect do
- begin
- Right := Right - Left;
- Left := 0;
- Bottom := Bottom - Top;
- Top := 0;
- end;
- WinProcs.GetClientRect(Handle, ClientRect);
- ClientH := ClientRect.Bottom - ClientRect.Top;
- if ( 0 < ClientH ) then Inc(ClientH);
-
- { Get a Window DC and wrap it in a Delphi Canvas }
- DC := GetWindowDC(Self.Handle);
- NCCanvas := TCanvas.Create;
- NCCanvas.Handle := DC;
- try
- with NCCanvas, WndRect, SysMetrics do
- begin
- if ( Mode = NCPaint_All ) then
- begin
- { Draw Left and Top edges of window frame, outer }
- Pen.Color := clBtnShadow;
- PolyLine([ Point(Left, Bottom - 1),
- Point(Left, Top),
- Point(Right, Top) ]);
- { Draw Bottom and Right edges of window frame, outer }
- Pen.Color := clWindowFrame;
- PolyLine([ Point(Left, Bottom - 1),
- Point(Right - 1, Bottom - 1),
- Point(Right - 1, Top - 1) ]);
- { Draw Left and Top edges of window frame, 1-pixel in }
- Pen.Color := clBtnHighlight;
- PolyLine([ Point(Left + 1, Bottom - 2),
- Point(Left + 1, Top + 1),
- Point(Right - 1, Top + 1) ]);
- { Draw Right and Bottom edges of window frame, 1-pixel in }
- Pen.Color := clBtnShadow;
- PolyLine([ Point(Left + 1, Bottom - 2),
- Point(Right - 2, Bottom - 2),
- Point(Right - 2, Top) ]);
-
- { Fill Remainder of Sizing border }
- Pen.Color := clBtnFace;
- for Extra := 2 to (Frame.cx - 1) do
- begin
- Brush.Color := clBtnFace;
- FrameRect(Rect(Left + Extra, Top + Extra,
- Right - Extra, Bottom - Extra));
- end;
-
- { Draw Left and Top Edge of Caption Area }
- Pen.Color := clBtnShadow;
- PolyLine([ Point(Frame.cx - 1, Bottom - 1 - Frame.cy - ClientH - ScrollH),
- Point(Frame.cx - 1, Frame.cy - 1),
- Point(Right - Frame.cx, Frame.cy - 1) ]);
- { Draw Bottom and Right Edge of Caption Area }
- Pen.Color := clBtnHighlight;
- PolyLine([ Point(Frame.cx - 1, Bottom - Frame.cy - ClientH - ScrollH),
- Point(Right - Frame.cx, Bottom - Frame.cy - ClientH - ScrollH),
- Point(Right - Frame.cx, Frame.cy - 1) ]);
- end;
-
- { Draw Caption }
- CaptionRect := Rect(Frame.cx + FSysMenuW + 1, Frame.cy,
- Right - Frame.cx - FMinMaxW,
- Frame.cy - 1 + CaptionH - 1);
- if ( (Mode = NCPaint_Activate) or
- ((Mode = NCPaint_All) and (GetActiveWindow = Self.Handle)) ) then
- begin { Need 'Active' Caption }
- Brush.Color := clActiveCaption;
- Font.Color := clCaptionText;
- end
- else
- begin { Need 'InActive' Caption }
- Brush.Color := clInactiveCaption;
- Font.Color := clInactiveCaptionText;
- end;
- FillRect(CaptionRect);
- with CaptionRect do
- begin
- { Assume center aligned }
- SetTextAlign(DC, TA_CENTER or TA_TOP);
- GetTextMetrics(DC, TM);
- CaptionPt := Point((Left + Right) div 2,
- Top + ((CaptionH - 1) - TM.tmHeight) div 2);
- if ( (Right - Left) < TextWidth(Caption) ) then
- begin { Switch caption to left align to mimic windows }
- SetTextAlign(DC, TA_LEFT or TA_TOP);
- CaptionPt.X := Left + 1;
- end;
- TextRect(CaptionRect, CaptionPt.X, CaptionPt.Y, Caption);
- end;
- end;
- finally
- NCCanvas.Free;
- ReleaseDC(Handle, DC);
- end; { try-finally }
- end;
-
-
- {
- WMNCHitTest handles the WM_NCHITTEST message.
- Modifies sizing hit codes to support fixed size windows.
- }
- procedure TForm3D.WMNCHitTest
- (
- var Msg: TWMNCHitTest
- );
- var
- HitCode : LongInt;
- begin
- inherited;
- HitCode := Msg.Result;
-
- { Lets resurrect the size corner }
- if ( HitCode = HTSIZE ) then HitCode := HTBOTTOMRIGHT;
-
- if ( not AllowResize ) then
- begin
- if ( (HitCode = HTLEFT) or (HitCode = HTRIGHT) or
- (HitCode = HTTOP) or (HitCode = HTBOTTOM) or
- (HitCode = HTTOPLEFT) or (HitCode = HTBOTTOMLEFT) or
- (HitCode = HTTOPRIGHT) or (HitCode = HTBOTTOMRIGHT) ) then
- begin
- HitCode := HTNOWHERE;
- end;
- end;
-
- Msg.Result := HitCode;
- end;
-
-
- {
- WMNCPaint handles WM_NCPAINT message.
- Calls default handler to paint non-client areas that have standard appearance.
- Calls NCPaint3D to paint modified non-client areas
- NOTE: Uses undocumented aspect of WM_NCPAINT message which allows a clipping
- region handle to be passed in the wParam of the message.
- This is used to avoid seeing the standard non-client areas flash before
- they are repainted by the 3D code.
- Ref. Undocumented Windows pg. 527, Thanks Andrew.
- }
- procedure TForm3D.WMNCPaint
- (
- var Msg: TWMNCPaint
- );
- var
- WndRect : TRect;
- ClientRect : TRect;
- ClientH : Integer;
- ScrollH : Integer;
- ClipRect : TRect;
- ClipRgn : THandle;
- HScrollVis : Boolean;
- VScrollVis : Boolean;
- begin
- if ( FEnable3D and (not IsIconic(Handle)) ) then
- begin
- { Let Windows draw the non-client areas that will not change }
- { Form props for window pos and size incorrect during resize here. }
- { Get Position directly from windows }
- WinProcs.GetWindowRect(Handle, WndRect);
- WinProcs.GetClientRect(Handle, ClientRect);
- ClientH := ClientRect.Bottom - ClientRect.Top;
- if ( 0 < ClientH ) then Inc(ClientH);
-
- HScrollVis := ScrollBarVisible(SB_HORZ, WndRect);
- VScrollVis := ScrollBarVisible(SB_VERT, WndRect);
-
- ScrollH := 0;
- if ( HScrollVis ) then ScrollH := SysMetrics.HScrollBtn.cy - 1;
-
- with WndRect, SysMetrics do
- begin
- { System Menu }
- if ( biSystemMenu in BorderIcons ) then
- begin
- ClipRect := Rect(Left + Frame.cx, Top + Frame.cy,
- Left + Frame.cx + TitleBitmap.cx + 1,
- Top + Frame.cy + TitleBitmap.cy);
- ClipRgn := CreateRectRgnIndirect(ClipRect);
- TMessage(Msg).wParam := ClipRgn;
- (self as TWinControl).DefaultHandler(Msg);
- DeleteObject(ClipRgn);
- end;
- { Min/Max buttons }
- if ( 0 < FMinMaxW ) then
- begin
- ClipRect := Rect(Right - Frame.cx - FMinMaxW, Top + Frame.cy,
- Right - Frame.cx, Top + Frame.cy + TitleBitmap.cy);
- ClipRgn := CreateRectRgnIndirect(ClipRect);
- TMessage(Msg).wParam := ClipRgn;
- (self as TWinControl).DefaultHandler(Msg);
- DeleteObject(ClipRgn);
- end;
- { Menubar }
- if ( Menu <> nil ) then
- begin
- ClipRect := Rect(Left + Frame.cx, Top + Frame.cy + CaptionH - Border.cy - 1,
- Right - Frame.cx, Bottom - Frame.cy - ClientH - ScrollH);
- ClipRgn := CreateRectRgnIndirect(ClipRect);
- TMessage(Msg).wParam := ClipRgn;
- (self as TWinControl).DefaultHandler(Msg);
- DeleteObject(ClipRgn);
- end;
- end;
-
- { Paint 3-D parts of nonclient area in 3-D style }
- NCPaint3D(NCPaint_All);
-
- { Now let windows paint scroll bars. Need to wait until here because scroll }
- { bars take advantage of normal borders for their outer edges and they }
- { our trounced in NCPaint3D. }
- with WndRect, SysMetrics do
- begin
- if ( HScrollVis ) then
- begin { Let Windows draw horz scroll bar }
- ClipRect := Rect(Left + (Frame.cx - 1), Bottom - (Frame.cy - 1) - HScrollBtn.cy,
- Right - (Frame.cx - 1), Bottom - (Frame.cy - 1));
- if ( VScrollVis ) then Dec(ClipRect.Right, VScrollBtn.cx - 1);
- ClipRgn := CreateRectRgnIndirect(ClipRect);
- TMessage(Msg).wParam := ClipRgn;
- (self as TWinControl).DefaultHandler(Msg);
- DeleteObject(ClipRgn);
- end;
- if ( VScrollVis ) then
- begin { Let Windows draw vert scroll bar }
- ClipRect := Rect(Right - (Frame.cx - 1) - VScrollBtn.cx, Bottom - Frame.cy - ClientH - ScrollH,
- Right - (Frame.cx - 1), Bottom - (Frame.cy - 1));
- if ( HScrollVis ) then Dec(ClipRect.Bottom, HScrollBtn.cy - 1);
- ClipRgn := CreateRectRgnIndirect(ClipRect);
- TMessage(Msg).wParam := ClipRgn;
- (self as TWinControl).DefaultHandler(Msg);
- DeleteObject(ClipRgn);
- end;
- if ( HScrollVis and VScrollVis ) then
- begin { Let Windows draw little box in corner }
- ClipRect := Rect(Right - (Frame.cx - 1) - (VScrollBtn.cx - 1),
- Bottom - (Frame.cy - 1) - (HScrollBtn.cy - 1),
- Right - (Frame.cx - 1) - 1, Bottom - (Frame.cy - 1) - 1);
- ClipRgn := CreateRectRgnIndirect(ClipRect);
- TMessage(Msg).wParam := ClipRgn;
- (self as TWinControl).DefaultHandler(Msg);
- DeleteObject(ClipRgn);
- end;
- end;
- Msg.Result := 0;
- end
- else
- begin
- { Use whatever behavior is standard for this system }
- DefaultHandler(Msg);
- end;
- end;
-
-
- {
- WMNCActivate handles the WM_NCACTIVATE message.
- Calls NCPaint3D to repaint the caption.
- Can NOT let windows have this message or it will trash our 3D borders.
- }
- procedure TForm3D.WMNCActivate
- (
- var Msg: TWMNCActivate
- );
- begin
- if ( FEnable3D and (not IsIconic(Handle)) ) then
- begin
- if ( Msg.Active ) then
- NCPaint3D(NCPaint_Activate)
- else
- NCPaint3D(NCPaint_Deactivate);
-
- Msg.Result := 1;
- end
- else
- begin
- DefaultHandler(Msg);
- end;
- end;
-
-
- end.
-