{-----------------------------------------------------------------------------
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: JvAlignListbox.PAS, released on 2000-11-22.

The Initial Developer of the Original Code is Peter Below <100113.1101@compuserve.com>
Portions created by Peter Below are Copyright (C) 2000 Peter Below.
All Rights Reserved.

Contributor(s): ______________________________________.

Last Modified: 2000-mm-dd

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:
-----------------------------------------------------------------------------}

{$I JVCL.INC}

unit JvPopupMemo;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, StdCtrls,
  JVCLVer;

type
  TJvPopupMemo = class(TMemo)
  private
    FAboutJVCL: TJVCLAboutInfo;
    FDesigntimeHeight: Integer;
    FFocusedHeight: Integer;
    FMaximumHeight: Integer;
    FCanvas: TControlCanvas;
    procedure CMTextChanged(var Msg: TMessage); message CM_TEXTCHANGED;
    procedure SetFocusedHeight(const Value: Integer);
    procedure SetMaximumHeight(const Value: Integer);
    procedure UpdateHeight;
    procedure ChangeScrollbar(Value: TScrollStyle);
  protected
    procedure DoEnter; override;
    procedure DoExit; override;
    procedure Change; override;
    procedure AdjustHeight;
    property Canvas: TControlCanvas read FCanvas;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    property FocusedHeight: Integer read FFocusedHeight write SetFocusedHeight;
  published
    property AboutJVCL: TJVCLAboutInfo read FAboutJVCL write FAboutJVCL stored False;
    property MaximumHeight: Integer read FMaximumHeight write SetMaximumHeight;
  end;

implementation

constructor TJvPopupMemo.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FFocusedHeight := Height;
  FMaximumHeight := 5 * Height;
  FCanvas := TControlCanvas.Create;
  FCanvas.Control := Self;
end;

destructor TJvPopupMemo.Destroy;
begin
  FCanvas.Free;
  inherited Destroy;
end;

procedure TJvPopupMemo.AdjustHeight;
const
  AlignFlags: array [TAlignment] of DWORD =
    (DT_LEFT, DT_CENTER, DT_RIGHT);
var
  OldRect, NewRect: TRect;
  NewHeight: Integer;
  S: string;
begin
  if not HandleAllocated then
    Exit;

  Perform(EM_GETRECT, 0, lparam(@OldRect));
  S := Text;

  { HACK ALERT! DrawText discards a trailing linebreak for measurement, so if
    the user hits return in the control and the new Line would require a
    larger memo we do not get the correct Value back. To fix that we add a
    blank just for the measurement if the last character is a linefeed. }
  if (Length(S) > 0) and (S[Length(S)] = #10) then
    S := S + ' ';
  Canvas.Font := Font;
  NewRect := OldRect;
  DrawText(Canvas.Handle, Pchar(S), Length(S), NewRect,
    DT_CALCRECT or DT_EDITCONTROL or DT_WORDBREAK or DT_NOPREFIX or
    DT_EXPANDTABS or
    AlignFlags[Alignment]);
  if OldRect.Bottom <> NewRect.Bottom then
  begin
    NewHeight := Height - (OldRect.Bottom - OldRect.Top) +
      (NewRect.Bottom - NewRect.Top);
    if NewHeight > MaximumHeight then
      ChangeScrollbar(ssVertical)
    else
      ChangeScrollbar(ssNone);
    FocusedHeight := NewHeight;
  end;
end;

procedure TJvPopupMemo.Change;
begin
  AdjustHeight;
  inherited Change;
end;

procedure TJvPopupMemo.ChangeScrollbar(Value: TScrollStyle);
var
  OldPos: Integer;
begin
  if ScrollBars <> Value then
  begin
    { Changing the scrollbar recreates the window and looses the caret
      position! }
    OldPos := SelStart;
    ScrollBars := Value;
    SelStart := OldPos;
    Perform(EM_SCROLLCARET, 0, 0);
  end;
end;

procedure TJvPopupMemo.CMTextChanged(var Msg: TMessage);
begin
  AdjustHeight;
  inherited;
end;

procedure TJvPopupMemo.DoEnter;
begin
  inherited DoEnter;
  FDesigntimeHeight := Height;
  UpdateHeight;
  // Height := FFocusedHeight;
end;

procedure TJvPopupMemo.DoExit;
begin
  inherited DoExit;
  Height := FDesigntimeHeight;
end;

procedure TJvPopupMemo.SetFocusedHeight(const Value: Integer);
begin
  if FFocusedHeight <> Value then
  begin
    if Value > MaximumHeight then
      FFocusedHeight := MaximumHeight
    else
      FFocusedHeight := Value;
    if Focused then
      UpdateHeight;
  end;
end;

procedure TJvPopupMemo.SetMaximumHeight(const Value: Integer);
begin
  if FMaximumHeight <> Value then
  begin
    FMaximumHeight := Value;
    if Value < FocusedHeight then
      FocusedHeight := Value;
  end;
end;

procedure TJvPopupMemo.UpdateHeight;
var
  Line: Integer;
begin
  if HandleAllocated and Focused then
  begin
    Height := FocusedHeight;
    if ScrollBars = ssNone then
    begin
      Line := Perform(EM_GETFIRSTVISIBLELINE, 0, 0);
      if Line > 0 then
        Perform(EM_LINESCROLL, 0, -Line);
    end;
  end;
end;

end.

