unit SlavaSplitter;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

type
  NaturalNumber = 1..High(Integer);

  TCanResizeEvent = procedure(Sender: TObject; var NewSize: Integer;
    var Accept: Boolean) of object;

  TResizeStyle = (rsNone, rsLine, rsUpdate, rsPattern);
  THandleAlign = (haLeft, haCenter, haRight);
  TClickOrientation = (coLeft, coRight, coUp, coDown);
  TDirection = (diLeft, diRight, diUp, diDown);

  TSlavaSplitter = class(TGraphicControl)
  private
    CMinHandledSize: Integer;
    FBorder1, FBorder2: TColor;
    BOver: Boolean;
    CTop, CBottom,
      CLeft, CRight: Integer;
    MouseX, MouseY: Integer;
    BmLeft, BmRight, BmUp, BmDown: TBitmap;
    BmLeftOver, BmRightOver, BmUpOver, BmDownOver: TBitmap;
    Ctrl1, Ctrl2: TControl;
    FOldControlSize: Integer;

    FSplitCursor: TCursor;
    FHandleCursor: TCursor;
    FActiveControl: TWinControl;
    FHandled: Boolean;
    FHandleSize: NaturalNumber;
    FHandleAlign: THandleAlign;
    FBrush: TBrush;
    FControl: TControl;
    FDownPos: TPoint;
    FLineDC: HDC;
    FLineVisible: Boolean;
    FMinSize: NaturalNumber;
    FMaxSize: Integer;
    FNewSize: Integer;
    FOldKeyDown: TKeyEvent;
    FOldSize: Integer;
    FPrevBrush: HBrush;
    FResizeStyle: TResizeStyle;
    FSplit: Integer;

    FOnCanResize: TCanResizeEvent;
    FOnMoved: TNotifyEvent;
    FOnPaint: TNotifyEvent;
    FClickOrientation: TClickOrientation;
    procedure AllocateLineDC;
    procedure CalcSplitSize(X, Y: Integer; var NewSize, Split: Integer);
    procedure DrawLine;
    function FindControl(aDirection: TDirection): TControl;
    procedure FocusKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure ReleaseLineDC;
    procedure SetHandled(Value: Boolean);
    procedure UpdateControlSize;
    procedure UpdateSize(X, Y: Integer);
    procedure SetClickOrientation(const Value: TClickOrientation);
    function GetAlign: TAlign;
    procedure SetAlign(const Value: TAlign);
    procedure SetHandleSize(const Value: NaturalNumber);
    procedure SetHandleAlign(const Value: THandleAlign);
    function GetWidth: Integer;
    procedure SetWidth(const Value: Integer);
    procedure SetHeight(Value: Integer);
    function GetHeight: Integer;
    procedure SetCursor(Value: TCursor);
    procedure SetHandleCursor(Value: TCursor);
    function IsValidBitmap(Bmp: TBitmap): Boolean;
    procedure SetBmDown(Value: TBitmap);
    procedure SetBmDownOver(Value: TBitmap);
    procedure SetBmLeft(Value: TBitmap);
    procedure SetBmLeftOver(Value: TBitmap);
    procedure SetBmRight(Value: Tbitmap);
    procedure SetBmRightOver(Value: TBitmap);
    procedure SetBmUp(Value: TBitmap);
    procedure SetBmUpOver(Value: TBitmap);
  protected
    function CanResize(var NewSize: Integer): Boolean; reintroduce; virtual;
    function DoCanResize(var NewSize: Integer): Boolean; virtual;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
      X, Y: Integer); override;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
      X, Y: Integer); override;
    procedure Paint; override;
    procedure RequestAlign;
{$IFDEF VER140} override;
{$ENDIF}
    procedure StopSizing; dynamic;

    function MouseInHandle: Boolean;

    procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;

    // protected -> no one has to know
    property ClickOrientation: TClickOrientation read FClickOrientation write
      SetClickOrientation;
    property ResizeStyle: TResizeStyle read FResizeStyle write FResizeStyle
      default rsPattern;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Loaded; override;
  published
    property Align: TAlign read GetAlign write SetAlign default alLeft;
    property Handled: Boolean read FHandled write SetHandled default True;
    property HandleSize: NaturalNumber read FHandleSize write SetHandleSize
      default 80;
    property HandleAlign: THandleAlign read FHandleAlign write SetHandleAlign
      default haCenter;
    property Color;
{$IFDEF VER120}
    property Constraints;
{$ENDIF}
    property MinSize: NaturalNumber read FMinSize write FMinSize default 30;
    property ParentColor;
    property Visible;
    property Width: Integer read GetWidth write SetWidth;

    property OnCanResize: TCanResizeEvent read FOnCanResize write FOnCanResize;
    property OnMoved: TNotifyEvent read FOnMoved write FOnMoved;
    property OnPaint: TNotifyEvent read FOnPaint write FOnPaint;
    property Height: Integer read GetHeight write SetHeight;
    property SplitterCursor: TCursor read FSplitCursor write SetCursor;
    property HandleCursor: TCursor read FHandleCursor write SetHandleCursor;

    property BitmapLeft: TBitmap read BmLeft write SetBmLeft;
    property BitmapLeftOver: TBitmap read BmLeftOver write SetBmLeftOver;
    property BitmapRight: TBitmap read BmRight write SetBmRight;
    property BitmapRightOver: Tbitmap read BmRightOver write SetBmRightOver;
    property BitmapUp: Tbitmap read BmUp write SetBmUp;
    property BitmapUpOver: Tbitmap read BmUpOver write SetBmUpOver;
    property BitmapDown: TBitmap read BmDown write SetBmDown;
    property BitmapDownOver: TBitmap read BmDownOver write SetBmDownOver;
    property BorderColor1: TColor read FBorder1 write FBorder1;
    property BorderColor2: TColor read FBorder2 write FBorder2;
  end;

procedure Register;

implementation

type
  TWinControlAccess = class(TWinControl);

procedure Register;
begin
  RegisterComponents('SlavaNap', [TSlavaSplitter]);
end;

constructor TSlavaSplitter.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  CMinHandledSize := 5;
  Align := alLeft;
  Width := 7;
  Cursor := crHSplit;
  HandleCursor := crDefault;
  FHandled := True;
  FHandleSize := 118;
  FHandleAlign := haCenter;
  FMinSize := 30;
  FResizeStyle := rsPattern;
  FOldSize := -1;
  FBorder1 := clWhite;
  FBorder2 := clGray;
  Color := clSilver;
  BmLeft := TBitmap.Create;
  BmRight := TBitmap.Create;
  BmUp := TBitmap.Create;
  BmDown := TBitmap.Create;
  BmLeftOver := TBitmap.Create;
  BmRightOver := TBitmap.Create;
  BmUpOver := TBitmap.Create;
  BmDownOver := Tbitmap.Create;
end;

destructor TSlavaSplitter.Destroy;
begin
  FBrush.Free;
  BmLeft.Free;
  BmRight.Free;
  BmUp.Free;
  BmDown.Free;
  BmLeftOver.Free;
  BmRightOver.Free;
  BmUpOver.Free;
  BmDownOver.Free;
  inherited Destroy;
end;

procedure TSlavaSplitter.AllocateLineDC;
begin
  FLineDC := GetDCEx(Parent.Handle, 0, DCX_CACHE or DCX_CLIPSIBLINGS
    or DCX_LOCKWINDOWUPDATE);
  {if ResizeStyle = rsPattern then
  begin
    if FBrush = nil then
    begin
      FBrush := TBrush.Create;
      // FBrush.Bitmap := AllocPatternBitmap(clBlack, clWhite);
    end;
    FPrevBrush := SelectObject(FLineDC, FBrush.Handle);
  end;}
end;

procedure TSlavaSplitter.DrawLine;
var
  P: TPoint;
begin
  FLineVisible := not FLineVisible;
  P := Point(Left, Top);
  if Align in [alLeft, alRight] then
    P.X := Left + FSplit
  else
    P.Y := Top + FSplit;
  with P do
    PatBlt(FLineDC, X, Y, Width, Height, PATINVERT);
end;

procedure TSlavaSplitter.ReleaseLineDC;
begin
  if FPrevBrush <> 0 then
    SelectObject(FLineDC, FPrevBrush);
  ReleaseDC(Parent.Handle, FLineDC);
  if FBrush <> nil then
  begin
    FBrush.Free;
    FBrush := nil;
  end;
end;

function TSlavaSplitter.FindControl(aDirection: TDirection): TControl;
var
  P: TPoint;
  I: Integer;
  R: TRect;
begin
  // Result := nil;
  P := Point(Left, Top);
  case aDirection of
    diLeft: Dec(p.X);
    diRight: Inc(p.X, Width);
    diUp: Dec(p.Y);
    diDown: Inc(p.Y, Height);
  end;
  {case Align of
    alLeft: Dec(P.X);
    alRight: Inc(P.X, Width);
    alTop: Dec(P.Y);
    alBottom: Inc(P.Y, Height);
    else Exit;
  end;}
  for I := 0 to Parent.ControlCount - 1 do
  begin
    Result := Parent.Controls[I];
    if Result.Visible and Result.Enabled then
    begin
      R := Result.BoundsRect;
      if (R.Right - R.Left) = 0 then
        if Align in [alTop, alLeft] then
          Dec(R.Left)
        else
          Inc(R.Right);
      if (R.Bottom - R.Top) = 0 then
        if Align in [alTop, alLeft] then
          Dec(R.Top)
        else
          Inc(R.Bottom);
      if PtInRect(R, P) then Exit;
    end;
  end;
  Result := nil;
end;

procedure TSlavaSplitter.RequestAlign;
begin
{$IFDEF VER120}
  inherited RequestAlign;
{$ENDIF}
  if (Cursor <> crVSplit) and (Cursor <> crHSplit) then Exit;
  if Align in [alBottom, alTop] then
    Cursor := crVSplit
  else
    Cursor := crHSplit;
end;

procedure TSlavaSplitter.Paint;
const
  XorColor = $00FFD8CE;
var
  R: TRect;
  Bm: TBitmap;
begin
  R := ClientRect;
  with Canvas do
  begin
    Pen.Color := Color;
    Pen.Style := psSolid;
    Brush.Color := Color;
    Pen.Mode := pmCopy;
    FillRect(ClientRect);
    Pen.Color := FBorder1;
    MoveTo(0, 0);
    if Align in [alLeft, alRight] then
      LineTo(0, Height)
    else
      Lineto(Width, 0);
    Pen.Color := FBorder2;
    MoveTo(Width - 1, Height - 1);
    if Align in [alLeft, alRight] then
      LineTo(Width - 1, -1)
    else
      LineTo(-1, Height - 1);
    Pen.Color := clBtnShadow;
  end;

  if Align in [alLeft, alRight] then
  begin
    case HandleAlign of
      haLeft:
        begin
          CTop := 2;
          CBottom := CTop + HandleSize;
        end;
      haCenter:
        begin
          CTop := (Height div 2) - (HandleSize div 2);
          CBottom := CTop + HandleSize;
        end;
      haRight:
        begin
          CTop := Height - HandleSize - 2;
          CBottom := CTop + HandleSize;
        end;
    end;
  end
  else
  begin
    case HandleAlign of
      haLeft:
        begin
          CLeft := 2;
          CRight := CLeft + HandleSize;
        end;
      haCenter:
        begin
          CLeft := (Width div 2) - (HandleSize div 2);
          CRight := CLeft + HandleSize;
        end;
      haRight:
        begin
          CLeft := Width - HandleSize - 2;
          CRight := CLeft + HandleSize;
        end;
    end;
  end;

  if Handled then
    case ClickOrientation of
      coUp, coDown:
        begin
          with Canvas do
          begin
            if Width > HandleSize then
            begin
              // Polygon([Point(CRight - 1, 0), Point(CLeft, 0),
              //   Point(CLeft, Height - 1), Point(CRight - 1, Height - 1),
              //   Point(CRight - 1, 0)]);
              // Pen.Color := clBtnHighlight;
              // PolyLine([Point(CLeft + 1, Height - 2),
              //   Point(CLeft + 1, 1), Point(CRight - 1, 1)]);

              // if BOver then
              // begin
              //   I := Brush.Color;
              //   Brush.Color := $00FFCFCF;
              //   FillRect(Rect(CLeft + 2, 2, CRight - 1, height - 1));
              //   Brush.Color := I;
              // end;

              // old code
              if ClickOrientation = coUp then
              begin
                if BOver then
                  Bm := BmUpOver
                else
                  Bm := BmUp;
              end
              else
              begin
                if BOver then
                  Bm := BmDownOver
                else
                  Bm := BmDown;
              end;
              if IsValidBitmap(Bm) then
                Draw(CLeft, 0, Bm);
            end;
          end;
        end;
      coLeft, coRight:
        begin
          with Canvas do
          begin
            if Height > HandleSize then
            begin
              // PolyLine([Point(0, CBottom - 1), Point(0, CTop),
              //   Point(Width - 1, CTop),  Point(Width - 1, CBottom - 1),
              //   Point(0, CBottom - 1)]);
              // Pen.Color := clBtnHighlight;
              // PolyLine([Point(Width - 2, CTop + 1),
              //   Point(1, CTop + 1), Point(1, CBottom - 1)]);

              // if BOver then
              // begin
              //   I := Brush.Color;
              //   Brush.Color := $00FFCFCF;
              //   FillRect(Rect(2, CTop + 2, Width - 1, CBottom - 1));
              //   Brush.Color := I;
              // end;

              // old code
              if ClickOrientation = coLeft then
              begin
                if BOver then
                  Bm := BmLeftOver
                else
                  Bm := BmLeft;
              end
              else
              begin
                if BOver then
                  Bm := BmRightOver
                else
                  Bm := BmRight;
              end;
              if IsValidBitmap(Bm) then
                Draw(0, CTop, Bm);
            end;
          end;
        end;
    end;

  //  if csDesigning in ComponentState then
  //    { Draw outline }
  //    with Canvas do
  //    begin
  //      Pen.Style := psDot;
  //      Pen.Mode := pmXor;
  //      Pen.Color := XorColor;
  //      Brush.Style := bsClear;
  //      Rectangle(0, 0, ClientWidth, ClientHeight);
  //    end;
  if Assigned(FOnPaint) then
    FOnPaint(Self);
end;

function TSlavaSplitter.DoCanResize(var NewSize: Integer): Boolean;
begin
  Result := CanResize(NewSize);
  if Result and (NewSize <= MinSize) then
    NewSize := MinSize;
      // MT this was the bug in the TSplitter component in Delphi 4 (NewSize := 0)
end;

function TSlavaSplitter.CanResize(var NewSize: Integer): Boolean;
begin
  Result := True;
  if Assigned(FOnCanResize) then
    FOnCanResize(Self, NewSize, Result);
end;

procedure TSlavaSplitter.MouseDown(Button: TMouseButton; Shift: TShiftState;
  X, Y: Integer);
var
  I: Integer;
begin
  inherited MouseDown(Button, Shift, X, Y);
  if Button = mbLeft then
  begin
    case Align of
      alLeft: FControl := Ctrl1;
      alRight: FControl := Ctrl2;
      alTop: FControl := Ctrl1;
      alBottom: FControl := Ctrl2;
    end;
    FDownPos := Point(X, Y);
    if Assigned(FControl) then
    begin
      if Align in [alLeft, alRight] then
      begin
        FMaxSize := Parent.ClientWidth - FMinSize;
        for I := 0 to Parent.ControlCount - 1 do
          with Parent.Controls[I] do
            if Align in [alLeft, alRight] then
              Dec(FMaxSize, Width);
        Inc(FMaxSize, FControl.Width);
      end
      else
      begin
        FMaxSize := Parent.ClientHeight - FMinSize;
        for I := 0 to Parent.ControlCount - 1 do
          with Parent.Controls[I] do
            if Align in [alTop, alBottom] then
              Dec(FMaxSize, Height);
        Inc(FMaxSize, FControl.Height);
      end;
      UpdateSize(X, Y);
      AllocateLineDC;
      with ValidParentForm(Self) do
        if ActiveControl <> nil then
        begin
          FActiveControl := ActiveControl;
          FOldKeyDown := TWinControlAccess(FActiveControl).OnKeyDown;
          TWinControlAccess(FActiveControl).OnKeyDown := FocusKeyDown;
        end;
      if ResizeStyle in [rsLine, rsPattern] then
        DrawLine;
    end;
  end;
end;

procedure TSlavaSplitter.UpdateControlSize;
begin
  if FNewSize <> FOldSize then
  begin
    case Align of
      alLeft:
        begin
          FControl.Width := FNewSize;
          Left := FControl.Width + 1;
        end;
      alTop:
        begin
          FControl.Height := FNewSize;
          Top := FControl.Height + 1;
        end;
      alRight:
        begin
          //          Parent.DisableAlign;
          try
            FControl.Left := FControl.Left + (FControl.Width - FNewSize);
            FControl.Width := FNewSize;
          finally
            //            Parent.EnableAlign;
          end;
{$IFNDEF VER120}
          if FControl.Width <> 0 then
          begin
            Left := FControl.Left;
            FControl.Left := Left + 1;
          end;
{$ENDIF}
        end;
      alBottom:
        begin
          //          Parent.DisableAlign;
          try
            FControl.Top := FControl.Top + (FControl.Height - FNewSize);
            FControl.Height := FNewSize;
          finally
            //            Parent.EnableAlign;
          end;
{$IFNDEF VER120}
          if FControl.Height <> 0 then
          begin
            Top := FControl.Top;
            FControl.Top := Top + 1;
          end;
{$ENDIF}
        end;
    end;
    Update;
    if Assigned(FOnMoved) then
      FOnMoved(Self);
    if FOldSize = 0 then
      case Align of
        alLeft: ClickOrientation := coLeft;
        alBottom: ClickOrientation := coDown;
        alRight: ClickOrientation := coRight;
        alTop: ClickOrientation := coUp;
      end;
    FOldSize := FNewSize;
  end;
end;

procedure TSlavaSplitter.CalcSplitSize(X, Y: Integer;
  var NewSize, Split: Integer);
var
  S: Integer;
begin
  if Align in [alLeft, alRight] then
    Split := X - FDownPos.X
  else
    Split := Y - FDownPos.Y;
  S := 0;
  case Align of
    alLeft: S := FControl.Width + Split;
    alRight: S := FControl.Width - Split;
    alTop: S := FControl.Height + Split;
    alBottom: S := FControl.Height - Split;
  end;
  NewSize := S;
  if S < FMinSize then
    NewSize := FMinSize
  else if S > FMaxSize then
    NewSize := FMaxSize;
  if S <> NewSize then
  begin
    if Align in [alRight, alBottom] then
      S := S - NewSize
    else
      S := NewSize - S;
    Inc(Split, S);
  end;
end;

procedure TSlavaSplitter.UpdateSize(X, Y: Integer);
begin
  CalcSplitSize(X, Y, FNewSize, FSplit);
end;

procedure TSlavaSplitter.MouseMove(Shift: TShiftState; X, Y: Integer);
var
  NewSize, Split: Integer;
begin
  inherited;
  if MouseInHandle then
  begin
    Cursor := FHandleCursor;
    if not BOver then
    begin
      BOver := True;
      Invalidate;
    end;
  end
  else
  begin
    Cursor := FSplitCursor;
    if BOver then
    begin
      BOver := False;
      Invalidate;
    end;
  end;
  MouseX := X;
  MouseY := Y;
  if (ssLeft in Shift) and Assigned(FControl) then
  begin
    CalcSplitSize(X, Y, NewSize, Split);
    if DoCanResize(NewSize) then
    begin
      if ResizeStyle in [rsLine, rsPattern] then
        DrawLine;
      FNewSize := NewSize;
      FSplit := Split;
      if ResizeStyle = rsUpdate then
        UpdateControlSize;
      if ResizeStyle in [rsLine, rsPattern] then
        DrawLine;
    end;
  end;
end;

procedure TSlavaSplitter.MouseUp(Button: TMouseButton; Shift: TShiftState;
  X, Y: Integer);
begin
  inherited;
  if Assigned(FControl) then
  begin
    if ResizeStyle in [rsLine, rsPattern] then
      DrawLine;
    if MouseInHandle then
    begin
      if FOldSize = -1 {// first time} then
      begin
        FNewSize := 0;
        if ClickOrientation in [coUp, coDown] then
          FOldControlSize := FControl.Height
        else
          FOldControlSize := FControl.Width;
      end
      else if FOldSize > 0 then
      begin
        FNewSize := 0; //
        FOldControlSize := FOldSize;
      end
      else
      begin
        FNewSize := FOldControlSize;
      end;
      case ClickOrientation of
        coUp: ClickOrientation := coDown;
        coDown: ClickOrientation := coUp;
        coLeft: ClickOrientation := coRight;
        coRight: ClickOrientation := coLeft;
      end;
    end;
    UpdateControlSize;
    StopSizing;
  end;
end;

procedure TSlavaSplitter.FocusKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if Key = VK_ESCAPE then
    StopSizing
  else if Assigned(FOldKeyDown) then
    FOldKeyDown(Sender, Key, Shift);
end;

procedure TSlavaSplitter.SetHandled(Value: Boolean);
begin
  FHandled := Value;
  case Align of
    alLeft, alRight: if Width < CMinHandledSize then
        Width := CMinHandledSize;
    alBottom, alTop: if Height < CMinHandledSize then
        Height := CMinHandledSize;
  end;
  RePaint;
end;

procedure TSlavaSplitter.StopSizing;
begin
  if Assigned(FControl) then
  begin
    if FLineVisible then
      DrawLine;
    FControl := nil;
    ReleaseLineDC;
    if Assigned(FActiveControl) then
    begin
      TWinControlAccess(FActiveControl).OnKeyDown := FOldKeyDown;
      FActiveControl := nil;
    end;
  end;
  if Assigned(FOnMoved) then
    FOnMoved(Self);
end;

procedure TSlavaSplitter.SetClickOrientation(
  const Value: TClickOrientation);
begin
  FClickOrientation := Value;
  Invalidate;
end;

procedure TSlavaSplitter.Loaded;
begin
  inherited Loaded;
  FSplitCursor := Cursor;
  if Align in [alLeft, alRight] then
  begin
    Ctrl1 := FindControl(diLeft);
    Ctrl2 := FindControl(diRight);
  end;
  if Align in [alTop, alBottom] then
  begin
    Ctrl1 := FindControl(diUp);
    Ctrl2 := FindControl(diDown);
  end;
end;

function TSlavaSplitter.MouseInHandle: Boolean;
begin
  if Align in [alLeft, alRight] then
    Result := Handled and PtInRect(Rect(0, CTop, Width, CBottom), Point(MouseX,
      MouseY))
  else
    Result := Handled and PtInRect(Rect(CLeft, 0, CRight, Height), Point(MouseX,
      MouseY));
end;

function TSlavaSplitter.GetAlign: TAlign;
begin
  Result := inherited Align;
end;

procedure TSlavaSplitter.SetAlign(const Value: TAlign);
var
  AValue: TClickOrientation;
begin
  if Value in [alNone, alClient] then
    raise Exception.Create('Value not allowed for ' + ClassName +
      ' component.');
  inherited Align := Value;
  AValue := coLeft;
  case Align of
    alLeft: AValue := coLeft;
    alRight: AValue := coRight;
    alTop: AValue := coUp;
    alBottom: AValue := coDown;
  end;
  ClickOrientation := AValue;
end;

procedure TSlavaSplitter.SetHandleSize(const Value: NaturalNumber);
begin
  FHandleSize := Value;
  Invalidate;
end;

procedure TSlavaSplitter.SetHandleAlign(const Value: THandleAlign);
begin
  FHandleAlign := Value;
  Invalidate;
end;

function TSlavaSplitter.GetWidth: Integer;
begin
  Result := inherited Width;
end;

procedure TSlavaSplitter.SetWidth(const Value: Integer);
begin
  if Handled and (Align in [alLeft, alRight]) and (Value < CMinHandledSize) then
    raise
      Exception.Create('Min. width for a handled TSlavaSplitter component is ' +
      IntToStr(CMinHandledSize));
  inherited Width := Value;
end;

procedure TSlavaSplitter.SetHeight(Value: Integer);
begin
  if Handled and (Align in [alTop, alBottom]) and (Value < CMinHandledSize) then
    raise
      Exception.Create('Min. height for a handled TSlavaSplitter component is ' +
      IntToStr(CMinHandledSize));
  inherited Height := Value;
end;

function TSlavaSplitter.GetHeight: Integer;
begin
  Result := inherited Height;
end;

procedure TSlavaSplitter.SetCursor(Value: TCursor);
begin
  FSplitCursor := Value;
end;

procedure TSlavaSplitter.SetHandleCursor(Value: TCursor);
begin
  FHandleCursor := Value;
end;

procedure TSlavaSplitter.CMMouseLeave(var Message: TMessage);
begin
  inherited;
  if BOver then
  begin
    BOver := False;
    Invalidate;
  end;
end;

function TSlavaSplitter.IsValidBitmap(Bmp: TBitmap): Boolean;
begin
  IsValidBitmap := False;
  if Bmp = nil then Exit;
  if not Assigned(Bmp) then Exit;
  if Bmp.Width < 3 then Exit;
  if Bmp.Height < 3 then Exit;
  IsValidBitmap := True;
end;

procedure TSlavaSplitter.SetBmDown(Value: TBitmap);
begin
  BmDown.Assign(Value);
  Invalidate;
end;

procedure TSlavaSplitter.SetBmDownOver(Value: TBitmap);
begin
  BmDownOver.Assign(Value);
  Invalidate;
end;

procedure TSlavaSplitter.SetBmLeft(Value: TBitmap);
begin
  BmLeft.Assign(Value);
  Invalidate;
end;

procedure TSlavaSplitter.SetBmLeftOver(Value: TBitmap);
begin
  BmLeftOver.Assign(Value);
  Invalidate;
end;

procedure TSlavaSplitter.SetBmRight(Value: TBitmap);
begin
  BmRight.Assign(Value);
  Invalidate;
end;

procedure TSlavaSplitter.SetBmRightOver(Value: TBitmap);
begin
  BmRightOver.Assign(Value);
  Invalidate;
end;

procedure TSlavaSplitter.SetBmUp(Value: TBitmap);
begin
  BmUp.Assign(Value);
  Invalidate;
end;

procedure TSlavaSplitter.SetBmUpOver(Value: TBitmap);
begin
  BmUpOver.Assign(Value);
  Invalidate;
end;

end.
