home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 April A / Pcwk4a98.iso / PROGRAM / DELPHI16 / Calmira / Src / VCL / FORMDRAG.PAS < prev    next >
Pascal/Delphi Source File  |  1997-02-18  |  10KB  |  330 lines

  1. {*********************************************************}
  2. {                                                         }
  3. {    Calmira Visual Component Library 1.0                 }
  4. {    by Li-Hsin Huang,                                    }
  5. {    released into the public domain January 1997         }
  6. {                                                         }
  7. {*********************************************************}
  8.  
  9. unit FormDrag;
  10.  
  11. { TFormDrag component }
  12.  
  13. { TFormDrag lets the user move and resize a form with a non-resizable
  14.   border, typically bsSingle.  It can simulate a "solid" drag like
  15.   Windows95, or for slower machines, it can use hollow boxes instead.
  16.   Just drop the component onto your form, and it is ready to use.
  17.  
  18.   Windows 3.x is generally not up to dynamically resizing the controls
  19.   during dragging, so TFormDrag hides all the controls and shows them
  20.   when the dragging has stopped.
  21.  
  22.   Note that you should not re-assign the following event handlers
  23.   of TForm at run-time: OnMouseMove, OnMouseDown, OnMouseUp,
  24.   OnPaint and OnResize.
  25.  
  26.   TFormDrag prevents some of these events from occuring when it
  27.   takes over the dragging, so that you need not be concerned with
  28.   any side effects -- just pretend the component is not there and
  29.   program normally.
  30.  
  31.   DragWidth
  32.     The size of the square in the bottom right corner reserved for
  33.     resizing the form.
  34.  
  35.   Hollow
  36.     Determines if the form is resized during dragging, or a hollow
  37.     rectangle used to represent the form's dimensions.
  38.  
  39.   MinWidth, MinHeight, MaxWidth, MaxHeight
  40.     Constrains the size of the form
  41.  
  42.   AllowMove, AllowSize
  43.     Enables the two operations of this component
  44.  
  45.   DragState (run-time and read only)
  46.     Indicates what kind of dragging is taking place.  Check this to
  47.     avoid executing code that could disrupt the operation.
  48. }
  49.  
  50. interface
  51.  
  52. uses
  53.   SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  54.   Forms, Dialogs;
  55.  
  56. type
  57.   TFormDragState = (fdNone, fdSolidMove, fdSolidSize, fdHollowMove, fdHollowSize);
  58.  
  59.   TFormDrag = class(TComponent)
  60.   private
  61.     { Private declarations }
  62.     FMouseMove : TMouseMoveEvent;
  63.     FMouseDown : TMouseEvent;
  64.     FMouseUp   : TMouseEvent;
  65.     FPaint     : TNotifyEvent;
  66.     FResize    : TNotifyEvent;
  67.     FDragState : TFormDragState;
  68.     FDragWidth : Integer;
  69.     FMinWidth  : Integer;
  70.     FMinHeight : Integer;
  71.     FMaxWidth  : Integer;
  72.     FMaxHeight : Integer;
  73.     FAllowMove : Boolean;
  74.     FAllowSize : Boolean;
  75.     FHollow    : Boolean;
  76.     xofs, yofs : Integer;
  77.     FormRect   : TRect;
  78.     procedure HandleMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  79.     procedure HandleMouseDown(Sender: TObject; Button: TMouseButton;
  80.       Shift: TShiftState; X, Y: Integer);
  81.     procedure HandleMouseUp(Sender: TObject; Button: TMouseButton;
  82.       Shift: TShiftState; X, Y: Integer);
  83.   protected
  84.     { Protected declarations }
  85.     procedure Loaded; override;
  86.     procedure StartHollowDrag;
  87.     procedure InverseRect;
  88.   public
  89.     { Public declarations }
  90.     constructor Create(AOwner: TComponent); override;
  91.     property DragState : TFormDragState read FDragState;
  92.   published
  93.     { Published declarations }
  94.     property DragWidth : Integer read FDragWidth write FDragWidth default 16;
  95.     property Hollow    : Boolean read FHollow write FHollow default False;
  96.     property MinWidth  : Integer read FMinWidth write FMinWidth default 0;
  97.     property MinHeight : Integer read FMinHeight write FMinHeight default 0;
  98.     property MaxWidth  : Integer read FMaxWidth write FMaxWidth default High(Integer);
  99.     property MaxHeight : Integer read FMaxHeight write FMaxHeight default High(Integer);
  100.     property AllowMove : Boolean read FAllowMove write FAllowMove default True;
  101.     property AllowSize : Boolean read FAllowSize write FAllowSize default True;
  102.   end;
  103.  
  104. procedure Register;
  105.  
  106.  
  107. implementation
  108.  
  109. uses MiscUtil;
  110.  
  111. var
  112.   { GDI objects used for drawing the resize boxes }
  113.   InversePen : HPen;
  114.  
  115. constructor TFormDrag.Create(AOwner: TComponent);
  116. begin
  117.   if not (AOwner is TForm) then
  118.     raise EInvalidOperation.Create('TFormDrag can only be placed on a form');
  119.  
  120.   inherited Create(AOwner);
  121.   FDragState := fdNone;
  122.   FDragWidth := 16;
  123.   FHollow    := False;
  124.   FMaxWidth  := High(Integer);
  125.   FMaxHeight := High(Integer);
  126.   FAllowMove := True;
  127.   FAllowSize := True;
  128. end;
  129.  
  130.  
  131. procedure TFormDrag.Loaded;
  132. begin
  133.   { The form's handlers must not be touched during design time,
  134.     otherwise incorrect events will be saved }
  135.  
  136.   inherited Loaded;
  137.   if not (csDesigning in ComponentState) then
  138.     with Owner as TForm do begin
  139.       { Save the form's original handlers... }
  140.       FMouseMove := OnMouseMove;
  141.       FMouseDown := OnMouseDown;
  142.       FMouseUp   := OnMouseUp;
  143.       FPaint     := OnPaint;
  144.       FResize    := OnResize;
  145.  
  146.       { ...and make the form call our handlers instead }
  147.       OnMouseMove := HandleMouseMove;
  148.       OnMouseDown := HandleMouseDown;
  149.       OnMouseUp   := HandleMouseUp;
  150.     end;
  151. end;
  152.  
  153.  
  154. procedure TFormDrag.StartHollowDrag;
  155. begin
  156.   { Create a suitable pen and set up the screen device context
  157.     ready for drawing }
  158.   InversePen := CreatePen(PS_SOLID, 1, ColorToRGB(clBlack));
  159.   { Obtain and draw the initial rectangle }
  160.   FormRect := TForm(Owner).BoundsRect;
  161.   InverseRect;
  162. end;
  163.  
  164.  
  165. procedure TFormDrag.InverseRect;
  166. var
  167.   ScreenDC: HDC;
  168.   OldPen     : HPen;
  169.   OldRop2    : Integer;
  170. begin
  171.   { Draws an inverse rectangle on the screen device context, the
  172.     coordinates specified by FormRect.  The rectangle is two
  173.     pixels thick but it is faster to draw two thin ones than to
  174.     use a thick pen }
  175.  
  176.   ScreenDC := GetDC(0);
  177.   OldRop2 := SetRop2(ScreenDC, R2_NOT);
  178.   OldPen := SelectObject(ScreenDC, InversePen);
  179.  
  180.   with FormRect do begin
  181.     MoveTo(ScreenDC, Left, Top);
  182.     LineTo(ScreenDC, Right-1, Top);
  183.     LineTo(ScreenDC, Right-1, Bottom-1);
  184.     LineTo(ScreenDC, Left, Bottom-1);
  185.     LineTo(ScreenDC, Left, Top);
  186.  
  187.     MoveTo(ScreenDC, Left-1, Top-1);
  188.     LineTo(ScreenDC, Right, Top-1);
  189.     LineTo(ScreenDC, Right, Bottom);
  190.     LineTo(ScreenDC, Left-1, Bottom);
  191.     LineTo(ScreenDC, Left-1, Top-1);
  192.   end;
  193.  
  194.   SetRop2(ScreenDC, OldRop2);
  195.   SelectObject(ScreenDC, OldPen);
  196.   ReleaseDC(0,ScreenDC);
  197. end;
  198.  
  199.  
  200.  
  201. procedure TFormDrag.HandleMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  202. begin
  203.   { During a solid drag, the form has its dimensions set each time the mouse
  204.     is moved.  During a hollow drag, the previous rectangle must be erased
  205.     (by drawing over it) before drawing the new one }
  206.  
  207.   with Owner as TForm do
  208.     case DragState of
  209.       fdNone :
  210.         if AllowSize then begin
  211.           if (X > ClientWidth-DragWidth) and (Y > ClientHeight-DragWidth) then begin
  212.             Cursor := crSizeNWSE;
  213.             Exit;
  214.           end
  215.           else begin
  216.             Cursor := crDefault;
  217.           end;
  218.           if Assigned(FMouseMove) then FMouseMove(Sender, Shift, X, Y);
  219.         end;
  220.  
  221.       fdSolidMove :
  222.         SetBounds(Left+X-xofs, Top+Y-yofs, Width, Height);
  223.  
  224.       fdSolidSize :
  225.         SetBounds(Left, Top,
  226.           Range(X+xofs, MinWidth, MaxWidth),
  227.           Range(Y+yofs, MinHeight, MaxHeight));
  228.  
  229.       fdHollowMove:
  230.         begin
  231.           InverseRect;
  232.           FormRect := Bounds(Left+X-xofs, Top+Y-yofs, Width, Height);
  233.           InverseRect;
  234.         end;
  235.  
  236.       fdHollowSize:
  237.         begin
  238.           InverseRect;
  239.           FormRect := Bounds(Left, Top, Range(X+xofs, MinWidth, MaxWidth),
  240.             Range(Y+yofs, MinHeight, MaxHeight));
  241.           InverseRect;
  242.         end;
  243.     end {case};
  244. end;
  245.  
  246.  
  247. procedure TFormDrag.HandleMouseDown(Sender: TObject; Button: TMouseButton;
  248.   Shift: TShiftState; X, Y: Integer);
  249. var i: Integer;
  250. begin
  251.   with Owner as TForm do
  252.   if (Button = mbLeft) and not (ssDouble in Shift)
  253.    and (WindowState <> WsMaximized) then begin
  254.     if (X > ClientWidth-DragWidth) and (Y > ClientHeight-DragWidth) and AllowSize then begin
  255.       { Start a resize operation }
  256.       xofs := Width - X;
  257.       yofs := Height - Y;
  258.  
  259.       if Hollow then begin
  260.         FDragState := fdHollowSize;
  261.         StartHollowDrag;
  262.       end
  263.       else begin
  264.         { Suppress OnPaint and OnResize }
  265.         FDragState := fdSolidSize;
  266.         OnPaint := nil;
  267.         OnResize := nil;
  268.         for i := 0 to ControlCount-1 do Controls[i].Hide;
  269.         Canvas.Brush.Color := Color;
  270.         Canvas.FillRect(Rect(0, 0, ClientWidth, ClientHeight));
  271.       end;
  272.     end
  273.     else if AllowMove then begin
  274.       { Start a move operation }
  275.       xofs := X;
  276.       yofs := Y;
  277.       if Hollow then begin
  278.         FDragState := fdHollowMove;
  279.         StartHollowDrag;
  280.       end
  281.       else FDragState := fdSolidMove;
  282.     end
  283.     else if Assigned(FMouseDown) then
  284.       { trigger form's original OnMouseDown event }
  285.       FMouseDown(Sender, Button, Shift, X, Y);
  286.   end
  287.   else if Assigned(FMouseDown) then
  288.      FMouseDown(Sender, Button, Shift, X, Y);
  289. end;
  290.  
  291.  
  292. procedure TFormDrag.HandleMouseUp(Sender: TObject; Button: TMouseButton;
  293.   Shift: TShiftState; X, Y: Integer);
  294. var i: Integer;
  295. begin
  296.   if (Button = mbLeft) and (FDragState <> fdNone) then
  297.   with Owner as TForm do begin
  298.     { End the drag operation }
  299.     if FDragState = fdSolidSize then begin
  300.       { Tell the form that it has just been resized, and force it
  301.         to paint if required.  }
  302.       FDragState := fdNone;
  303.       if Assigned(FResize) then FResize(Owner);
  304.       if Assigned(FPaint) then FPaint(Owner);
  305.       OnResize := FResize;
  306.       OnPaint := FPaint;
  307.       for i := 0 to ControlCount-1 do Controls[i].Show;
  308.     end
  309.     else if FDragState in [fdHollowSize, fdHollowMove] then begin
  310.       { Set the new coordinates of the form and clean up the
  311.         graphics stuff }
  312.       ReleaseCapture;
  313.       InverseRect;
  314.       BoundsRect := FormRect;
  315.       DeleteObject(InversePen);
  316.     end;
  317.     FDragState := fdNone;
  318.   end
  319.   else
  320.     if Assigned(FMouseUp) then FMouseUp(Sender, Button, Shift, X, Y);
  321. end;
  322.  
  323. procedure Register;
  324. begin
  325.   RegisterComponents('Samples', [TFormDrag]);
  326. end;
  327.  
  328.  
  329. end.
  330.