{ *************************************************************************** }
{                                                                             }
{ EControl Syntax Editor SDK                                                  }
{                                                                             }
{ Copyright (c) 2004 - 2008 EControl Ltd., Zaharov Michael                    }
{     www.econtrol.ru                                                         }
{     support@econtrol.ru                                                     }
{                                                                             }
{ *************************************************************************** }
{$I ecSyntEdit.INC}

unit ecStylesCombo;

interface

uses Windows, Messages, Classes, Graphics, Controls, stdctrls, Dialogs, SysUtils,
     ecSyntMemo, ecSyntAnal;

type

  TUserStyleComboOptions = set of (uscoIncludeLexer, uscoIncludeUser, uscoNoEdit,
                           uscoAutoWidth, uscoStyledItems);

  TUserStylesCombo = class(TCustomComboBox)
  private
    FEditor: TCustomSyntaxMemo;
    FOptions: TUserStyleComboOptions;
    FStlList: TList;
    FCurStyle: string;
    procedure SetEditor(const Value: TCustomSyntaxMemo);
    procedure SetAction(const Value: TBasicAction);
    function _GetAction: TBasicAction;
    function MeasItem(Style: TSyntaxFormat): TSize;
    procedure SetOptions(const Value: TUserStyleComboOptions);
    procedure SetCurStyle(const Value: string);
  protected
    procedure Change; override;
    procedure DropDown; override;
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
    procedure MeasureItem(Index: Integer; var Height: Integer); override;
    procedure DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure InitiateAction; override;
    property Action: TBasicAction read _GetAction write SetAction;
  published
    property Editor: TCustomSyntaxMemo read FEditor write SetEditor;
    property Options: TUserStyleComboOptions read FOptions write SetOptions
      default [uscoIncludeLexer, uscoIncludeUser, uscoAutoWidth];
  end;

implementation

{ TUserStylesCombo }

procedure TUserStylesCombo.Change;
var ur: TUserRange;
begin
  inherited;
  if Assigned(FEditor) then
   begin
     ur := FEditor.CurrentUserRange;
     if ur <> nil then ur.Style := Text
      else FEditor.CreateUserRange(False, Text);
     FEditor.Invalidate;
   end;
end;

constructor TUserStylesCombo.Create(AOwner: TComponent);
begin
  inherited;
  FStlList := TList.Create;
  ControlStyle := ControlStyle + [csActionClient] - [csSetCaption];
  FOptions := [uscoIncludeLexer, uscoIncludeUser, uscoAutoWidth];
end;

destructor TUserStylesCombo.Destroy;
begin
  FStlList.Free;
  inherited;
end;

procedure TUserStylesCombo.DropDown;
var w, i, t: integer;
  procedure AddStyles(Coll: TStylesCollection);
  var i: integer;
  begin
    for i := 0 to Coll.Count - 1 do
     begin
      FStlList.Add(Coll[i]);
      Items.Add(Coll[i].DisplayName);
     end;
  end;
begin
  Items.Clear;
  FStlList.Clear;
  if Assigned(FEditor) then
   begin
     if (uscoIncludeUser in Options) and Assigned(FEditor.UserStyles) then
       AddStyles(FEditor.UserStyles.Styles);
     if (uscoIncludeLexer in Options) and Assigned(FEditor.SyntObj) then
       AddStyles(FEditor.SyntObj.Owner.Formats)
   end;
  w := 0;
  if uscoAutoWidth in FOptions then
   begin
     for i := 0 to FStlList.Count - 1 do
      begin
        t := MeasItem(TSyntaxFormat(FStlList[i])).cx;
        if t > w then w := t;
      end;
     if Items.Count > 6 then
      Inc(w, GetSystemMetrics(SM_CXVSCROLL));
     Inc(w, 5);
   end;
  if w < Width then w := Width;
  SendMessage(Handle, CB_SETDROPPEDWIDTH, w, 0);
  if Style <> csDropDown then ItemIndex := Items.IndexOf(FCurStyle);
  inherited;
end;

function TUserStylesCombo._GetAction: TBasicAction;
begin
  Result := inherited Action;
end;

procedure TUserStylesCombo.SetCurStyle(const Value: string);
begin
  if Value <> FCurStyle then
   begin
    FCurStyle := Value;
    if Style = csDropDown then  Text := FCurStyle
      else
        begin
          FStlList.Clear;
          Items.Clear;
          Items.Add(FCurStyle);
          ItemIndex := 0;//Items.IndexOf(FCurStyle);
        end;
    Invalidate;
   end;
end;

procedure TUserStylesCombo.InitiateAction;
var ur: TUserRange;
begin
  inherited;
  if not Assigned(FEditor) then Exit;
  ur := FEditor.CurrentUserRange;
  Enabled := (ur <> nil) or (FEditor.SelLength > 0);
  if ur <> nil then SetCurStyle(ur.Style)
               else SetCurStyle('');
end;

procedure TUserStylesCombo.Notification(AComponent: TComponent;
  Operation: TOperation);
begin
  inherited;
  if (FEditor = AComponent) and (Operation = opRemove) then
    FEditor := nil;
end;

procedure TUserStylesCombo.SetAction(const Value: TBasicAction);
begin
  inherited Action := Value;
  if Value = nil then
    ControlStyle := ControlStyle + [csActionClient];
end;

procedure TUserStylesCombo.SetEditor(const Value: TCustomSyntaxMemo);
begin
  if FEditor <> Value then
   begin
     FEditor := Value;
     if Assigned(FEditor) then
       FEditor.FreeNotification(Self);
   end;
end;

function TUserStylesCombo.MeasItem(Style: TSyntaxFormat): TSize;
begin
{$IFDEF EC_VCL6_UP}
  if Style <> nil then
   begin
    if uscoStyledItems in FOptions then
      Canvas.Font := Style.Font;
    Result := Canvas.TextExtent(Style.DisplayName);
   end else
{$ENDIF}
   begin
    Result.cx := 0;
    Result.cy := 17;
   end;
end;

procedure TUserStylesCombo.DrawItem(Index: Integer; Rect: TRect;
  State: TOwnerDrawState);
begin
  if odComboBoxEdit in State then
   begin
    Canvas.FillRect(Rect);
    Canvas.TextOut(Rect.Left + 2, Rect.Top, FCurStyle);
   end
  else
   if (Index >= 0) and (Index < FStlList.Count) then
    with TSyntaxFormat(FStlList[Index]) do
     begin
      Canvas.Font := Font;
      if odSelected in State then Canvas.Font.Color := clHighlightText else
       begin
        if BgColor = clNone then Canvas.Brush.Color := Self.Color
         else Canvas.Brush.Color := BgColor;
        if Font.Color = clNone then
          Canvas.Font.Color := Self.Font.Color;
       end;
      Canvas.FillRect(Rect);
      Canvas.TextOut(Rect.Left + 2, Rect.Top, DisplayName);
     end;
end;

procedure TUserStylesCombo.MeasureItem(Index: Integer;
  var Height: Integer);
begin
  if (Index >= 0) and (Index < FStlList.Count) then
   Height := MeasItem(TSyntaxFormat(FStlList[Index])).cy
  else
   inherited;
end;

procedure TUserStylesCombo.SetOptions(const Value: TUserStyleComboOptions);
begin
  if FOptions <> Value then
   begin
    FOptions := Value;
    if uscoStyledItems in FOptions then Style := csOwnerDrawVariable else
    if uscoNoEdit in FOptions      then Style := csDropDownList
                                   else Style := csDropDown;
   end;
end;

end.

