{ ------------------------------------------------------------- }
{ Purpose : Next Common 6                                       }
{ By      : Bojan Nikolic                                       }
{ For     : BergSoft                                            }
{ ------------------------------------------------------------- }
{ Copyright (C) BergSoft.net 2011. All Rights Reserved.         }
{ ------------------------------------------------------------- }
{$I ..\NxSuite6.inc}
unit NxStandardReg6;

interface

uses
  { Standard }
  Classes, Types, Forms, Graphics,
  { Standard.Design }
  DesignIntf, DesignEditors, VCLEditors, TypInfo, ImgList,
  { Next Standard 6 }
  NxIntf6, NxEdit6, NxControls6, NxStdCtrls6, NxXMLDoc6, NxHTML6,
  { Next Standard 6.Design }
  NxVersionDlg6, NxMultilineDlg6;

const
  urlSupport = 'http://www.bergsoft.net/en-us/support.htm';
  urlUsersSection = 'http://user.bergsoft.net/';
  State: array[Boolean] of string = ('Enable', 'Disable');

type
  { TNextSuiteComponentEditor6 }

  TNextSuiteComponentEditor6 = class(TDefaultEditor)
  public
    function GetVerb(Index: Integer): string; override;
    function GetVerbCount: Integer; override;
    procedure ExecuteVerb(Index: Integer); override;
  end;

{$IFNDEF WIDESTRING_PROPERTY}
  TWideStringProperty = TStringProperty;
{$ENDIF}

  { TNxMultilinePropertyEditor6 }

  TNxMultilinePropertyEditor6 = class(TWideStringProperty)
  public
    function GetAttributes: TPropertyAttributes; override;
    procedure Edit; override;
  end;

  { TStringColorProperty }

  TStringColorProperty = class(TStringProperty
{$IFDEF CUSTOM_PROPERTY_DRAWING}
  , ICustomPropertyDrawing80,
    ICustomPropertyDrawing, ICustomPropertyListDrawing
{$ENDIF}
  )
  public
    function GetAttributes: TPropertyAttributes; override;
    procedure GetValues(Proc: TGetStrProc); override;
{$IFDEF CUSTOM_PROPERTY_DRAWING}
    { ICustomPropertyListDrawing }
    procedure ListMeasureHeight(const Value: string; ACanvas: TCanvas;
      var AHeight: Integer);
    procedure ListMeasureWidth(const Value: string; ACanvas: TCanvas;
      var AWidth: Integer);
    procedure ListDrawValue(const Value: string; ACanvas: TCanvas;
      const ARect: TRect; ASelected: Boolean);
    { ICustomPropertyDrawing }
    procedure PropDrawName(ACanvas: TCanvas; const ARect: TRect;
      ASelected: Boolean);
    procedure PropDrawValue(ACanvas: TCanvas; const ARect: TRect;
      ASelected: Boolean);
    { ICustomPropertyDrawing80 }
    function PropDrawNameRect(const ARect: TRect): TRect;
    function PropDrawValueRect(const ARect: TRect): TRect;
{$ENDIF}
  end;

  TNxColorProperty2 = class(TIntegerProperty
{$IFDEF CUSTOM_PROPERTY_DRAWING}
  , ICustomPropertyDrawing,
    ICustomPropertyListDrawing, ICustomPropertyDrawing80
{$ENDIF}
  )
  public
    procedure Edit; override;
    function GetAttributes: TPropertyAttributes; override;
    function GetValue: string; override;
    procedure GetValues(Proc: TGetStrProc); override;
    procedure SetValue(const Value: string); override;

{$IFDEF CUSTOM_PROPERTY_DRAWING}
    { ICustomPropertyListDrawing }
    procedure ListMeasureHeight(const Value: string; ACanvas: TCanvas;
      var AHeight: Integer);
    procedure ListMeasureWidth(const Value: string; ACanvas: TCanvas;
      var AWidth: Integer);
    procedure ListDrawValue(const Value: string; ACanvas: TCanvas;
      const ARect: TRect; ASelected: Boolean);

    { ICustomPropertyDrawing }
    procedure PropDrawName(ACanvas: TCanvas; const ARect: TRect;
      ASelected: Boolean);
    procedure PropDrawValue(ACanvas: TCanvas; const ARect: TRect;
      ASelected: Boolean);
    { ICustomPropertyDrawing80 }
    function PropDrawNameRect(const ARect: TRect): TRect;
    function PropDrawValueRect(const ARect: TRect): TRect;
{$ENDIF}
  end;

  TNxStylePaintProperty = class(TPropertyEditor)
  public
    function GetAttributes: TPropertyAttributes; override;
    procedure GetProperties(Proc: TGetPropProc); override;
    function GetValue: string; override;
  end;

  { TNxNumberEditEditor }

  TNxNumberEditEditor = class(TComponentEditor)
  public
    function GetVerb(Index: Integer): string; override;
    function GetVerbCount: Integer; override;
    procedure ExecuteVerb(Index: Integer); override;
  end;

  { TNxImageIndexPropertyEditor6 }

  TNxImageIndexPropertyEditor6 = class(TIntegerProperty
{$IFDEF CUSTOM_PROPERTY_DRAWING}
    , ICustomPropertyListDrawing
{$ENDIF}
    )
  public
    function GetAttributes: TPropertyAttributes; override;
    procedure GetValues(Proc: TGetStrProc); override;
    function GetImageListAt(Index: Integer): TCustomImageList; virtual;
{$IFDEF CUSTOM_PROPERTY_DRAWING}
    { ICustomPropertyListDrawing }
    procedure ListMeasureHeight(const Value: string; ACanvas: TCanvas;
      var AHeight: Integer);
    procedure ListMeasureWidth(const Value: string; ACanvas: TCanvas;
      var AWidth: Integer);
    procedure ListDrawValue(const Value: string; ACanvas: TCanvas;
      const ARect: TRect; ASelected: Boolean);
{$ENDIF}
  end;

function CheckForUpdates: Boolean;
procedure ShowVersion(Control: INxVersionControl);

procedure Register;

implementation

uses
  { Standard }
  SysUtils, Dialogs, Controls,
  { WinApi }
  Windows, ShellAPI,
  { Next Standard 6 }
  NxConsts6, NxClasses6, NxGraphics6, NxStylePaint6;

function CheckForUpdates: Boolean;
var
  Net: TNxNetSource;
  Version: string;
begin
  Net := TNxNetSource.Create(nil);

  try
    Net.Url := 'http://www.bergsoft.net/updates.php';

    try
      Net.Active := True;

      Version := Net.AsString;

      if Version = vrNextSuite then
        ShowMessage('Your copy of NextSuite (' + vrNextSuite + ') is up to date.')
      else
        if MessageDlg('NextSuite ' + Version + ' is now available - you have ' + vrNextSuite + '. Do you want to visit Users section?',
          mtInformation, [mbYes, mbNo], 0) = mrYes then
            ShellExecute(0, 'open', urlUsersSection, '', '', SW_SHOWNORMAL);

      Result := True;

    except
      { Can't connect or read }
      Result := False;
    end;

  finally
    Net.Free;
  end;
end;

procedure ShowVersion(Control: INxVersionControl);
var
  Dialog: TVersionsDialog;
begin
  Dialog := TVersionsDialog.Create(nil);
  try
    { Add Versions into ListBox }
    with Dialog.VersionsListBox.Items do
    begin
      { NextSuite Version }
      Add('NextSuite ' + vrNextSuiteDesc);

      Add('  ' + Control.ControlName + ' ' + Control.Version);
    end;

    Dialog.ShowModal;

  finally
    FreeAndNil(Dialog);
  end;
end;

function PaintColorBox(const Value: string; ACanvas: TCanvas;
  const ARect: TRect; ASelected: Boolean): TRect;

  function ColorToBorderColor(AColor: TColor): TColor;
  begin
    if (GetRValue(AColor) > 192)
      or (GetGValue(AColor) > 192)
      or (GetBValue(AColor) > 192)
        then Result := clBlack
        else if ASelected
              then Result := clWhite
                else Result := AColor;
  end;

var
  OldPenColor, OldBrushColor: TColor;
  ColorRect: TRect;
begin
  ColorRect := ARect;
  ColorRect.Right := (ARect.Bottom - ARect.Top) + ARect.Left;

  Result := ColorRect;

  with ACanvas do
  begin
    OldPenColor := Pen.Color;
    OldBrushColor := Brush.Color;

    { Border }
    Pen.Color := Brush.Color;
    Rectangle(ColorRect);

    { Color }
    InflateRect(ColorRect, -1, -1);

    { clNone, if invalid color }
    if StrToColor(Value) = clNone then
    begin
      Pen.Color := clBlack;
      Brush.Color := clWhite;
      Rectangle(ColorRect);

      Pen.Color := clRed;
      Polyline([
        Point(ARect.Left + 2, ARect.Top + 2),
        Point(ARect.Right - 4, ARect.Bottom - 2)
      ]);
    end else
    begin
      Brush.Color := StrToColor(Value);
      Pen.Color := ColorToBorderColor(ColorToRGB(Brush.Color));
      Rectangle(ColorRect);
    end;

    Brush.Color := OldBrushColor;
    Pen.Color := OldPenColor;
  end;

  Result := Rect(Result.Right, ARect.Top, ARect.Right, ARect.Bottom);
end;

procedure Register;
begin
  { Next Editors 6 }
  RegisterComponents('Next Editors 6', [TNxEdit6, TNxMemo6, TNxSpinEdit6,
    TNxComboBox6, TNxCheckComboBox6, TNxButtonEdit6, TNxDatePicker6,
    TNxTimePicker6, TNxCheckBox6, TNxFontComboBox6, TNxColorComboBox6, TNxColorPicker6,
    TNxIconPicker6, TNxMaskEdit6, TNxTagsEdit6, TNxGridPicker6]);

  { Next Editors 6 }
  RegisterComponents('Next Editors 6', [TNxExecuteButton6, TNxDropDownButton6]);
  RegisterComponents('Next Editors 6', [TNxTextValidator6]);

  { Next Standard 6 }
  RegisterComponents('Next Standard 6', [TNxColorScheme6, TNxToolbar6, TNxToolPalette6, TNxXMLDocument6, TNxCSVDocument6, TNxStylesSheet6]);

  RegisterPropertyEditor(TypeInfo(string), TNxCSSRule, 'Color', TStringColorProperty);
  RegisterPropertyEditor(TypeInfo(string), TNxCSSRule, 'BackgroundColor', TStringColorProperty);

  RegisterPropertyEditor(TypeInfo(TColor), TNxControl6, 'BorderColor', TNxColorProperty2);
  RegisterPropertyEditor(TypeInfo(TColor), TNxPaintStyle6, 'Color', TNxColorProperty2);
  RegisterPropertyEditor(TypeInfo(TColor), TNxPaintStyle6, 'BackgroundColor', TNxColorProperty2);
  RegisterComponentEditor(TNxNumberEdit6, TNxNumberEditEditor);
end;

{ TNextSuiteComponentEditor6 }

procedure TNextSuiteComponentEditor6.ExecuteVerb(Index: Integer);
begin
  inherited;

  { Version }
  if Index = GetVerbCount - 2 then
  begin
    ShowVersion(GetComponent as INxVersionControl);
  end;

  { Support is last Verb }
  if Index = Pred(GetVerbCount) then
  begin
    ShellExecute(0, 'open', urlSupport, '', '', SW_SHOWNORMAL);
  end;
end;

function TNextSuiteComponentEditor6.GetVerb(Index: Integer): string;
begin
  if Index = GetVerbCount - 3 then Result := '-';
  if Index = GetVerbCount - 2 then Result := 'V&ersion...';
  if Index = GetVerbCount - 1 then Result := '&Support...';
end;

function TNextSuiteComponentEditor6.GetVerbCount: Integer;
begin
  Result := 3;
end;

{ TNxMultilinePropertyEditor6 }

function WordCount(const S: string; const Delims: TSysCharSet): Integer;
var
  L, I: Cardinal;
begin
  Result := 0;
  I := 1;
  L := Length(S);
  while I <= L do
  begin
    while (I <= L) and CharInSet(S[I], Delims) do Inc(I);
    if I <= L then Inc(Result);
    while (I <= L) and not(CharInSet(S[I], Delims)) do Inc(I);
  end;
end;

function WordPosition(const N: Integer; const S: string;
  const WordDelims: TSysCharSet): Integer;
var
  Count, I: Integer;
begin
  Count := 0;
  I := 1;
  Result := 0;
  while (I <= Length(S)) and (Count <> N) do begin
    { skip over delimiters }
    while (I <= Length(S)) and (CharInSet(S[I], WordDelims)) do Inc(I);
    { if we're not beyond end of S, we're at the start of a word }
    if I <= Length(S) then Inc(Count);
    { if not finished, find the end of the current word }
    if Count <> N then
      while (I <= Length(S)) and not (CharInSet(S[I], WordDelims)) do Inc(I)
    else Result := I;
  end;
end;

function ExtractWord(N: Integer; const S: string;
  const WordDelims: TSysCharSet): string;
var
  I: Integer;
  Len: Integer;
begin
  Len := 0;
  I := WordPosition(N, S, WordDelims);
  if I <> 0 then
    { find the end of the current word }
    while (I <= Length(S)) and not(CharInSet(S[I], WordDelims)) do
    begin
      { add the I'th character to result }
      Inc(Len);
      SetLength(Result, Len);
      Result[Len] := S[I];
      Inc(I);
    end;
  SetLength(Result, Len);
end;

procedure TNxMultilinePropertyEditor6.Edit;
var
  Temp: string;
  Component: TPersistent;
  i, N: Integer;
begin
  with TMultilineEditDialog.Create(Application) do
    try
      Component := GetComponent(0);

      if Component is TComponent
        then Caption := TComponent(Component).Name + '.' + GetName
        else Caption := GetName;

      Temp := GetStrValue;
      N := WordCount(Temp, [#13, #10]);

      Memo.Lines.Clear;
      for i := 1 to N do Memo.Lines.Add(ExtractWord(i, Temp, [#13, #10]));

      Memo.MaxLength := GetEditLimit;

      if ShowModal = mrOk then
      begin
        Temp := Memo.Text;
        while (Length(Temp) > 0) and (Temp[Length(Temp)] < ' ') do
          System.Delete(Temp, Length(Temp), 1);

        SetStrValue(Temp);
      end;

    finally
      Free;
    end;

end;

function TNxMultilinePropertyEditor6.GetAttributes: TPropertyAttributes;
begin
  Result := inherited GetAttributes + [paAutoUpdate, paDialog];
end;

{ TStringColorProperty }

function TStringColorProperty.GetAttributes: TPropertyAttributes;
begin
  Result := [paMultiSelect, paDialog, paValueList, paRevertable];
end;

procedure TStringColorProperty.GetValues(Proc: TGetStrProc);
var
  i: Integer;
  Color: TWebColor;
begin
  { Delphi Colors }
  GetColorValues(Proc);

  { Web Colors }
  for i := 0 to 140 do
  begin
    Color := WebColors[i];
    Proc(Color[cnColorName]);
  end;
end;

{$IFDEF CUSTOM_PROPERTY_DRAWING}
procedure TStringColorProperty.ListDrawValue(const Value: string; ACanvas: TCanvas;
  const ARect: TRect; ASelected: Boolean);
var
  ValueRect: TRect;
begin
  ValueRect := PaintColorBox(Value, ACanvas, ARect, ASelected);
  DefaultPropertyListDrawValue(Value, ACanvas, ValueRect, ASelected);
end;

procedure TStringColorProperty.ListMeasureHeight(const Value: string;
  ACanvas: TCanvas; var AHeight: Integer);
begin

end;

procedure TStringColorProperty.ListMeasureWidth(const Value: string;
  ACanvas: TCanvas; var AWidth: Integer);
begin
  AWidth := AWidth + ACanvas.TextHeight('M');
end;

procedure TStringColorProperty.PropDrawName(ACanvas: TCanvas;
  const ARect: TRect; ASelected: Boolean);
begin
  DefaultPropertyDrawName(Self, ACanvas, ARect);
end;

function TStringColorProperty.PropDrawNameRect(const ARect: TRect): TRect;
begin
  Result := ARect;
end;

procedure TStringColorProperty.PropDrawValue(ACanvas: TCanvas;
  const ARect: TRect; ASelected: Boolean);
begin
  PaintColorBox(GetVisualValue, ACanvas, ARect, ASelected)
end;

function TStringColorProperty.PropDrawValueRect(const ARect: TRect): TRect;
begin
  Result := Rect(ARect.Left, ARect.Top, (ARect.Bottom - ARect.Top) + ARect.Left, ARect.Bottom);
end;
{$ENDIF}

{ TNxColorProperty2 }

procedure TNxColorProperty2.Edit;
begin
  inherited;

end;

function TNxColorProperty2.GetAttributes: TPropertyAttributes;
begin
  Result := [paMultiSelect, paDialog, paValueList, paRevertable];
end;

function TNxColorProperty2.GetValue: string;
begin
  Result := ColorToString(TColor(GetOrdValue));
end;

procedure TNxColorProperty2.GetValues(Proc: TGetStrProc);
var
  i: Integer;
  Color: TWebColor;
begin
  { Delphi Colors }
  GetColorValues(Proc);

  { Web Colors }
  for i := 0 to 140 do
  begin
    Color := WebColors[i];
    Proc(Color[cnColorName]);
  end;
end;

{$IFDEF CUSTOM_PROPERTY_DRAWING}
procedure TNxColorProperty2.ListDrawValue(const Value: string; ACanvas: TCanvas;
  const ARect: TRect; ASelected: Boolean);
var
  ValueRect: TRect;
begin
  ValueRect := PaintColorBox(Value, ACanvas, ARect, ASelected);
  DefaultPropertyListDrawValue(Value, ACanvas, ValueRect, ASelected);
end;

procedure TNxColorProperty2.ListMeasureHeight(const Value: string;
  ACanvas: TCanvas; var AHeight: Integer);
begin

end;

procedure TNxColorProperty2.ListMeasureWidth(const Value: string;
  ACanvas: TCanvas; var AWidth: Integer);
begin
  AWidth := AWidth + ACanvas.TextHeight('M');
end;

procedure TNxColorProperty2.PropDrawName(ACanvas: TCanvas; const ARect: TRect;
  ASelected: Boolean);
begin
  DefaultPropertyDrawName(Self, ACanvas, ARect);
end;

function TNxColorProperty2.PropDrawNameRect(const ARect: TRect): TRect;
begin
  Result := ARect;
end;

procedure TNxColorProperty2.PropDrawValue(ACanvas: TCanvas; const ARect: TRect;
  ASelected: Boolean);
begin
  PaintColorBox(GetVisualValue, ACanvas, ARect, ASelected)
end;

function TNxColorProperty2.PropDrawValueRect(const ARect: TRect): TRect;
begin
  Result := Rect(ARect.Left, ARect.Top, (ARect.Bottom - ARect.Top) + ARect.Left, ARect.Bottom);
end;
{$ENDIF}

procedure TNxColorProperty2.SetValue(const Value: string);
begin
  SetOrdValue(StrToColor(Value));
end;

{ TNxNumberEditEditor }

procedure TNxNumberEditEditor.ExecuteVerb(Index: Integer);
begin
  with GetComponent as TNxNumberEdit6 do
    case Index of
      0:  if ednDecimals in NumericEditOptions then
            NumericEditOptions := NumericEditOptions - [ednDecimals]
          else
            NumericEditOptions := NumericEditOptions + [ednDecimals];
      1:  if ednSigns in NumericEditOptions then
            NumericEditOptions := NumericEditOptions - [ednSigns]
          else
            NumericEditOptions := NumericEditOptions + [ednSigns];

    end;

end;

function TNxNumberEditEditor.GetVerb(Index: Integer): string;
begin
  with GetComponent as TNxNumberEdit6 do
    case Index of
      0: Result := State[ednDecimals in NumericEditOptions] + ' &Decimals';
      1: Result := State[ednSigns in NumericEditOptions] + ' &Signs';
    end;
end;

function TNxNumberEditEditor.GetVerbCount: Integer;
begin
  Result := 2;
end;

{ TNxStylePaintProperty }

function TNxStylePaintProperty.GetAttributes: TPropertyAttributes;
begin
  Result := [paReadOnly, paSubProperties];
end;

procedure TNxStylePaintProperty.GetProperties(Proc: TGetPropProc);
var
  Components: IDesignerSelections;
  Ref: IInterfaceComponentReference;
begin
  Components := TDesignerSelections.Create;
  if Supports(GetIntfValue, IInterfaceComponentReference, Ref) then
  begin
    Components.Add(Ref.GetComponent);

    if Components.Count > 0 then
      GetComponentProperties(Components, tkProperties, Designer, Proc);
  end;
end;

function TNxStylePaintProperty.GetValue: string;
begin
  Result := '(StylePaint)';
end;

{ TNxImageIndexPropertyEditor6 }

function TNxImageIndexPropertyEditor6.GetAttributes: TPropertyAttributes;
begin
  Result := [paMultiSelect, paValueList, paRevertable];
end;

function TNxImageIndexPropertyEditor6.GetImageListAt(Index: Integer): TCustomImageList;
begin
  Result := nil;
end;

procedure TNxImageIndexPropertyEditor6.GetValues(Proc: TGetStrProc);
var
  ImgList: TCustomImageList;
  i: Integer;
begin
  ImgList := GetImageListAt(0);
  if Assigned(ImgList) then
    for i := 0 to ImgList.Count - 1 do
      Proc(IntToStr(i));
end;

{$IFDEF CUSTOM_PROPERTY_DRAWING}

procedure TNxImageIndexPropertyEditor6.ListDrawValue(
  const Value: string; ACanvas: TCanvas; const ARect: TRect;
  ASelected: Boolean);
var
  ImgList: TCustomImageList;
  X: Integer;
begin
  ImgList := GetImageListAt(0);
  ACanvas.FillRect(ARect);
  X := ARect.Left + 2;
  if Assigned(ImgList) then
  begin
    ImgList.Draw(ACanvas, X, ARect.Top + 2, StrToInt(Value));
    Inc(X, ImgList.Width);
  end;
  ACanvas.TextOut(X + 3, ARect.Top + 1, Value);
end;

procedure TNxImageIndexPropertyEditor6.ListMeasureHeight(
  const Value: string; ACanvas: TCanvas; var AHeight: Integer);
var
  ImgList: TCustomImageList;
begin
  ImgList := GetImageListAt(0);
  AHeight := ACanvas.TextHeight(Value) + 2;
  if Assigned(ImgList) and (ImgList.Height + 4 > AHeight) then
    AHeight := ImgList.Height + 4;
end;

procedure TNxImageIndexPropertyEditor6.ListMeasureWidth(
  const Value: string; ACanvas: TCanvas; var AWidth: Integer);
var
  ImgList: TCustomImageList;
begin
  ImgList := GetImageListAt(0);
  AWidth := ACanvas.TextWidth(Value) + 4;
  if Assigned(ImgList) then
    Inc(AWidth, ImgList.Width);
end;

{$ENDIF}

end.
