unit UMoveablePanel;
{ ********************************************************************************* }
{ (c) GNU                                                                           }
{ author: Heiko Tietze                                                              }
{ version: 1.0                                                                      }
{ date: 11.12.2004                                                                  }
{ description: basic definition of a panel that can me moved and resized            }
{              moveable panels are used in ScrabbleGrid for StonePanel,             }
{              StatisticPanel and the Chat                                          }
{ ********************************************************************************* }

{$I Def.inc}

interface

uses {$IFDEF VCL}
     Controls, ExtCtrls, Forms, Graphics,
     {$ELSE}
     QControls, QExtCtrls, QForms, QGraphics,
     {$ENDIF}
     Classes, Types;

type TPanelState=(stNormal, stSizing, stMoving, stDisabled);
     TMoveablePanel=class(TCustomPanel)
         private
            FCaption : TPanel;
            FAlignPanel : TPanel;
            FState   : TPanelState;
            FTemp    : TPoint; //start point at mouse down event
            procedure MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
            procedure MouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer);
            procedure MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
            procedure SetAnchors(Sender: TObject);
            procedure SetState(const Value: TPanelState);
         public
            constructor Create(aOwner:TComponent);override;
            destructor Destroy;override;
            procedure Resize(Sender : TObject);
            property Caption : TPanel read FCaption write FCaption;
            property State : TPanelState read FState write SetState;
         end; //TStonePanel

implementation

constructor TMoveablePanel.Create(aOwner: TComponent);
begin
  inherited Create(aOwner);
  FCaption:=TPanel.Create(self);
  with FCaption do
  begin
     Parent:=self as TWinControl;
     Align:=alBottom; Height:=18;
     BevelOuter:=bvNone; Color:=clGreen; Font.Color:=clWhite;
     Caption:='moveable panel';
     OnMouseDown:=MouseDown;
     OnMouseMove:=MouseMove;
     OnMouseUp:=MouseUp;
  end;
  FAlignPanel:=TPanel.Create(FCaption);
  with FAlignPanel do
  begin
     Parent:=FCaption;
     Align:=alLeft;
     Color:=FCaption.Color;
     BevelOuter:=bvLowered;
     Caption:='+';
     Width:=20;
     OnClick:=SetAnchors;
  end;
  Anchors:=[akLeft, akTop];
  FState:=stNormal;
end;

destructor TMoveablePanel.Destroy;
begin
   FCaption.Free;
   inherited;
end;

procedure TMoveablePanel.MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
   if (x>FCaption.Width-10) and
      (((FCaption.Align=alBottom) and (y>FCaption.Height-5)) or
       ((FCaption.Align=alTop) and (y<5))) then
   begin
      FState:=stSizing;
      FTemp.X:=Left;
      case FCaption.Align of
        alBottom : FTemp.Y:=Top;
        alTop    : FTemp.Y:=Top+Height;
      end;
   end else
   if (x>10) and (x<FCaption.Width-10) and (y>5) and (y<FCaption.Height-5) then
   begin
     FState:=stMoving;
     FTemp:=ScreenToClient(Mouse.CursorPos);
   end;
   if FState=stMoving then Anchors:=[];
end;

procedure TMoveablePanel.MouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer);
var p:TPoint;
begin
   p:=ScreenToClient(Mouse.CursorPos);
   case FState of
   stSizing : begin
                 Width:=Left+p.x-FTemp.x;
                 case FCaption.Align of
                   alBottom : Height:=Top+p.y-FTemp.y;
                   alTop :    begin
                                Top:=Top+p.y;
                                Height:=FTemp.y-Top;
                              end;
                 end; //case
              end;
   stMoving : begin
                 FAlignPanel.BevelOuter:=bvRaised;
                 FAlignPanel.Caption:='->';
                 Left:=Left+p.x-FTemp.x;
                 Top:=Top+p.y-FTemp.y;
              end;
   end;//case
   FCaption.Cursor:=crDefault;
   if (x>10) and (x<FCaption.Width-10) and (y>5) and (y<FCaption.Height-5) then FCaption.Cursor:=crSizeAll;
   if (x>FCaption.Width-10) then
      case FCaption.Align of
        alBottom : if (y>FCaption.Height-5) then FCaption.Cursor:=crSizeNWSE;
        alTop : if (y<5) then FCaption.Cursor:=crSizeNESW;
      end;
end;

procedure TMoveablePanel.MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
   FState:=stNormal;
   if Top+Height>Application.MainForm.ClientRect.Bottom then Top:=Application.MainForm.ClientRect.Bottom-Height-10;
   if Left+Width>Application.MainForm.ClientRect.Right then Left:=Application.MainForm.ClientRect.Right-Width-10;
   if Width<64 then Width:=64; if Height<32 then Height:=32;
   if Top<10 then Top:=10; if Left<10 then Left:=10;
   Resize(self);
end;

procedure TMoveablePanel.Resize(Sender: TObject);
begin
   inherited Resize;
end;

procedure TMoveablePanel.SetAnchors(Sender: TObject);
begin
   if (Sender as TPanel).BevelOuter<>bvLowered then
   begin
     Anchors:=Anchors+[akLeft,akTop];
     (Sender as TPanel).BevelOuter:=bvLowered;
     (Parent as TForm).OnResize(self);
     (Sender as TPanel).Caption:='+';
   end;
end;

procedure TMoveablePanel.SetState(const Value: TPanelState);
begin
  if Value<>FState then
  begin
     FState:=Value;
     if FState=stDisabled then
     begin
        FCaption.Color:=clGray;
        FAlignPanel.Color:=clGray;
     end else
     begin
        FCaption.Color:=clGreen;
        FAlignPanel.Color:=clGreen;
     end;
  end;
end;

end.
