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

interface

uses
  { Standard }
  Classes, Types, Windows, Graphics, Controls, StdCtrls,
  {$IFDEF UI_TYPES}UITypes,{$ENDIF}
  { Next Standard 6 }
  NxIntf6, NxTypes6, NxClasses6, NxControls6,
  NxStyles6, NxStylePaint6,
  { NextGrid 6 }
  NxColumns6;

type
  TNxIndicatorLocation = (ilHeader, ilInsertRow, ilRow);

  { INxGridStylePaint }

  INxGridStylePaint = interface(INxStylePaint)
    ['{F20C07A6-CE2E-45AA-AF45-152679691356}']
    function GetColumn: TNxColumn6;
    function GetFooterSize: TSize;
    function GetHeaderSize: TSize;
    function GetHotTrackHeaders: Boolean;
    procedure SetColumn(const Value: TNxColumn6);
    procedure SetLocation(const Value: TNxColumnLocation);
    procedure PaintFooter(FooterRect: TRect);
    procedure PaintHeader(HeaderRect: TRect; State: TNxButtonState);
    procedure PaintHeaderButton(ButtonRect: TRect; State: TNxButtonState);
    procedure PaintInactiveHeader(HeaderRect: TRect);
    procedure PaintIndicator(IndicatorRect: TRect; Location: TNxIndicatorLocation; Selected, Highlighted: Boolean);
    property HotTrackHeaders: Boolean read GetHotTrackHeaders;
  end;

  {$M+}

  { TNxNativeGridPartStylePaint }

  TNxNativeGridPartStylePaint = class(TNxNativeStylePaint, INxGridStylePaint)
  private
    FColumn: TNxColumn6;
    FLocation: TNxColumnLocation;
    function GetColumn: TNxColumn6;
    function GetFooter: TNxColumnFooter;
    function GetHeader: TNxColumnHeader;
    function GetHotTrackHeaders: Boolean;
    procedure SetColumn(const Value: TNxColumn6);
    procedure SetLocation(const Value: TNxColumnLocation);
  protected
    { Polygon Drawings }
    procedure DrawSortIndicator(Location: TPoint; Kind: TNxSortKind); virtual;
    { Painting }
    procedure PaintClassicHeader(HeaderRect: TRect; State: TNxButtonState); virtual;
    procedure PaintNativeStyledHeader(HeaderRect: TRect; State: TNxButtonState); virtual;
    procedure PaintVCLStyledHeader(HeaderRect: TRect; State: TNxButtonState); virtual;
    { Properties }
  public
    { Get Metrics }
    function GetArrowSize: TSize;
    function GetFooterSize: TSize;
    function GetHeaderSize: TSize;
    function GetHeaderContentRect(HeaderRect: TRect): TRect; virtual;
    function GetHeaderTextColor(State: TNxButtonState): TColor; virtual;
    { Painting }
    procedure PaintFooter(FooterRect: TRect); virtual;
    procedure PaintFooterContent(FooterRect: TRect); virtual;
    procedure PaintHeader(HeaderRect: TRect; State: TNxButtonState); virtual;
    procedure PaintHeaderBackground(HeaderRect: TRect; State: TNxButtonState); virtual;
    procedure PaintHeaderButton(ButtonRect: TRect; State: TNxButtonState); virtual;
    procedure PaintHeaderContent(HeaderRect: TRect; State: TNxButtonState); virtual;
    procedure PaintInactiveHeader(HeaderRect: TRect); virtual;
    procedure PaintIndicator(IndicatorRect: TRect; Location: TNxIndicatorLocation; Selected, Highlighted: Boolean); virtual;
    { Properties }
    property ArrowSize: TSize read GetArrowSize;
    property Column: TNxColumn6 read GetColumn write SetColumn;
    property Footer: TNxColumnFooter read GetFooter;
    property Header: TNxColumnHeader read GetHeader;
    property HotTrackHeaders: Boolean read GetHotTrackHeaders;
    property Location: TNxColumnLocation read FLocation write SetLocation;
  end;

  { TNxModernGridPartStylePaint }

  TNxModernGridPartStylePaint = class(TNxNativeGridPartStylePaint)
  public
    procedure PaintHeaderBackground(HeaderRect: TRect; State: TNxButtonState); override;
    procedure PaintHeaderButton(ButtonRect: TRect; State: TNxButtonState); override;
    procedure PaintInactiveHeader(HeaderRect: TRect); override;
    procedure PaintIndicator(IndicatorRect: TRect; Location: TNxIndicatorLocation; Selected, Highlighted: Boolean); override;
    procedure PaintProgressBar(BarRect: TRect); override;
    procedure PaintProgressChunk(ChunkRect: TRect); override;
    procedure PaintToolButton(ButtonRect: TRect; State: TNxButtonState); override;
  end;

  { TNxUserDefinedStylePaint }

  TNxUserDefinedStylePaint = class(TNxNativeGridPartStylePaint, INxUserDefinedStyle)
  private
    FButtonColor: TColor;
    FButtonHoverColor: TColor;
    FButtonPressedColor: TColor;
    FHeaderHoverColor: TColor;
    FHeaderPressedColor: TColor;
    FLinesColor: TColor;
    procedure SetButtonHoverColor(const Value: TColor);
    procedure SetButtonPressedColor(const Value: TColor);
    procedure SetHeaderHoverColor(const Value: TColor);
    procedure SetHeaderPressedColor(const Value: TColor);
    procedure SetButtonColor(const Value: TColor);
  public
    constructor Create(AOwner: TComponent); override;
    procedure PaintHeaderBackground(HeaderRect: TRect; State: TNxButtonState); override;
    procedure PaintIndicator(IndicatorRect: TRect; Location: TNxIndicatorLocation; Selected,
      Highlighted: Boolean); override;
    procedure PaintInactiveHeader(HeaderRect: TRect); override;
  published
    property ButtonColor: TColor read FButtonColor write SetButtonColor;
    property ButtonHoverColor: TColor read FButtonHoverColor write SetButtonHoverColor;
    property ButtonPressedColor: TColor read FButtonPressedColor write SetButtonPressedColor;
    property HeaderHoverColor: TColor read FHeaderHoverColor write FHeaderHoverColor default cl3DLight;
    property HeaderPressedColor: TColor read FHeaderPressedColor write FHeaderPressedColor default cl3DLight;
    property LinesColor: TColor read FLinesColor write FLinesColor default clBtnShadow;
  end;

implementation

uses
  { Standard }
  SysUtils, MaskUtils, ExtCtrls, Math,
  { Next Standard 6 }
  NxConsts6, NxTheme6, NxGraphics6, NxHTML6;

{ TNxNativeGridPartStylePaint }

procedure TNxNativeGridPartStylePaint.DrawSortIndicator(Location: TPoint; Kind: TNxSortKind);
begin
  with Canvas, Location do
  begin
    Pen.Color := clGray;
    Brush.Color := Pen.Color;
    case Kind of
      skAscending:
        Polygon([
          Point(X, Y + ArrowSize.cy),
          Point(X + ArrowSize.cy, Y),
          Point(X + ArrowSize.cx, Y + ArrowSize.cy)
        ]);
      skDescending:
        Polygon([
          Point(X, Y),
          Point(X + ArrowSize.cy, Y + ArrowSize.cy),
          Point(X + ArrowSize.cx, Y)
        ]);
    end;
  end;
end;

function TNxNativeGridPartStylePaint.GetArrowSize: TSize;
begin
  Result := DotToPixel(Size(8, 4));
end;

function TNxNativeGridPartStylePaint.GetColumn: TNxColumn6;
begin
  Result := FColumn;
end;

function TNxNativeGridPartStylePaint.GetFooter: TNxColumnFooter;
begin
  Result := Column.Footer;
end;

function TNxNativeGridPartStylePaint.GetFooterSize: TSize;
var
  WrapKind: TNxWrapKind;
begin
  Unset(Result);

  with Column.Footer do
  begin
    if DisplayMode <> dmImageOnly then
    begin
      WrapKind := wkEllipsis;
      if MultiLine then WrapKind := wkWordWrap;

      Result.cx := GetTextSize(Canvas.Handle, Bounds(0, 0, Control.ClientWidth, 0), GetDisplayText, WrapKind).cx;
    end;

    if DisplayMode <> dmTextOnly then
    begin
      if Result.cx > 0 then
        Inc(Result.cx, pdTextToIcon);

      if Assigned(Glyph.Graphic)
        and not Glyph.Graphic.Empty then
      begin
        Inc(Result.cx, Glyph.Width);
      end;
    end;

    if Result.cx > 0 then
      Inc(Result.cx, pdDouble);
  end;
end;

function TNxNativeGridPartStylePaint.GetHeader: TNxColumnHeader;
begin
  Result := Column.Header;
end;

function TNxNativeGridPartStylePaint.GetHeaderContentRect(HeaderRect: TRect): TRect;
begin
  Result := HeaderRect;
  if Header.ShowButton then Dec(Result.Right, szFilterDropButtonWidth + pdStandard);
end;

function TNxNativeGridPartStylePaint.GetHeaderSize: TSize;
begin
  Unset(Result);

  with Column.Header do
  begin
    if DisplayMode <> dmImageOnly then
    begin
      Canvas.Font.Assign(Font);
      Result.cx := GetTextSize(Canvas, Caption, True).cx;
    end;

    if DisplayMode <> dmTextOnly then
    begin
      if Result.cx > 0 then
        Inc(Result.cx, pdTextToIcon);

      if Assigned(Glyph.Graphic)
        and not Glyph.Graphic.Empty then
      begin
        Inc(Result.cx, Glyph.Width);
      end;
    end;

    if Result.cx > 0 then
      Inc(Result.cx, pdDouble);
  end;
end;

function TNxNativeGridPartStylePaint.GetHeaderTextColor(State: TNxButtonState): TColor;
begin
  Result := Canvas.Font.Color;
  if CanStyle(soVCLStyles) then
  begin
    Canvas.Font.Color := clNone;
    Result := TNxHeaderStyle6.GetTextColor(Control, Result, State);
  end;
end;

function TNxNativeGridPartStylePaint.GetHotTrackHeaders: Boolean;
begin
  Result := CanStyle(soVCLStyles) or CanStyle(soNativeStyles);
end;

procedure TNxNativeGridPartStylePaint.PaintClassicHeader(HeaderRect: TRect; State: TNxButtonState);
var
  InRect, InvertRect: TRect;
begin
  InRect := HeaderRect;
  InflateRect(InRect, -1, -1);

  with Canvas, HeaderRect do
  begin
    Brush.Color := Column.Header.Color;
    FillRect(InRect);

    if Self.Location = clAlone then
    begin
      Frame3D(Canvas, HeaderRect, clBtnHighlight, clBtnShadow, 1);
      InvertRect := Rect(Left - 1, Top - 1, Right, Bottom);
    end else
    begin

      { Highlight }
      Pen.Color := clBtnHighlight; { Highlight }
      Polyline([Point(Left, Top), Point(Right, Top)]);

      if Self.Location = clLeftSide
        then Polyline([Point(Left, Top + 1), Point(Left, Bottom - 1)]) else
      begin
        Polyline([Point(Left, Top + 2), Point(Left, Bottom - 2)]);
        Pixels[Left, Top + 1] := Column.Header.Color;
        Pixels[Left, Bottom - 2] := Column.Header.Color;
      end;

      { Shadow }
      Pen.Color := clBtnShadow;
      Polyline([Point(Left, Bottom - 1), Point(Right, Bottom - 1)]);

      if Self.Location = clRightSide
        then Polyline([Point(Right - 1, Top), Point(Right - 1, Bottom - 1)]) else
      begin
        Polyline([Point(Right - 1, Top + 2), Point(Right - 1, Bottom - 2)]);
        Pixels[Right - 1, Top + 1] := Column.Header.Color;
        Pixels[Right - 1, Bottom - 2] := Column.Header.Color;
      end;

      InvertRect := Rect(Left, Top, Right - 1, Bottom);
    end;

    if bsPressed in State then
      with HeaderRect do
      begin
        CopyMode := cmDstInvert;
        CopyRect(InvertRect, Canvas, InvertRect);
        CopyMode := cmSrcCopy;
      end;
  end;

end;

procedure TNxNativeGridPartStylePaint.PaintFooter(FooterRect: TRect);
begin
  { Paint Caption, Glyph & Sorting Arrow }
  if doContent in Footer.DrawingOptions then
  begin
    PaintFooterContent(FooterRect);
  end;
end;

procedure TNxNativeGridPartStylePaint.PaintFooterContent(FooterRect: TRect);
var
  CaptionRect, ContentRect: TRect;
  TextSize, GlyphSize, ContentSize: TSize;
  GlyphPos, TextPos: TPoint;
  WrapKind: TNxWrapKind;
  S: WideString;
  HasGlyph: Boolean;
  Bitmap: TBitmap;
begin
  { Init. vars }
  WrapKind := wkNone;

  with Footer do
  begin
    HasGlyph := (DisplayMode <> dmTextOnly)
      and Assigned(Glyph)
      and Assigned(Glyph.Graphic)
      and not Glyph.Graphic.Empty;

    Canvas.Font.Assign(Font);

    { Background }
    with Canvas do
    begin
      Brush.Color := Color;
      FillRect(FooterRect);
    end;

    { Text }
    S := GetDisplayText;

    { Default }
    Unset(TextSize);
    Unset(GlyphSize);
    Unset(ContentSize);

    { Has Text? }
    if DisplayMode <> dmImageOnly then
    begin
      { Multiline? }
      WrapKind := wkEllipsis;
      if MultiLine then WrapKind := wkWordWrap;

      { Measure }
      TextSize := GetTextSize(Canvas.Handle, FooterRect, S, WrapKind);
      ContentSize := TextSize;
    end;

    if HasGlyph then
    begin
      GlyphSize := Size(Glyph.Width, Glyph.Height);
    end;

    if Orientation = orVertical then
      TextSize := Rotate(TextSize);

    { Incl. Padding }
    if (TextSize.cx > 0) and HasGlyph
      then Inc(TextSize.cx, pdTextToIcon);

    case Orientation of
      orHorizontal: ContentSize := Size(TextSize.cx + GlyphSize.cx,
        Max(TextSize.cy, GlyphSize.cy));
      orVertical: ContentSize := Max(TextSize, GlyphSize);
    end;

    ContentRect := Bounds(FooterRect.Left, FooterRect.Top,
      ContentSize.cx, FooterRect.Bottom - FooterRect.Top);

    { Shift content TRect }
    case Alignment of
      taLeftJustify: OffsetRect(ContentRect, pdDouble, 0);
      taRightJustify: OffsetRect(ContentRect, RectWidth(FooterRect) - ContentSize.cx - pdDouble, 0);
      Classes.taCenter: OffsetRect(ContentRect, RectWidth(FooterRect) div 2 - ContentSize.cx div 2, 0);
    end;

    { Set Glyph & Text positions }
    case Orientation of
      orHorizontal:
      begin

        TextPos.X := ContentRect.Left;

        if HasGlyph then
        begin
          GlyphPos.X := ContentRect.Left;
          GlyphPos.Y := CenterInRect(ContentRect, Glyph.Width, Glyph.Height).Y;
          Inc(TextPos.X, Glyph.Width + pdTextToIcon);
        end;

        TextPos.Y := CenterInRect(ContentRect, TextSize.cx, TextSize.cy).Y;

      end;

      orVertical:
      begin
        TextPos.Y := FooterRect.Bottom - pdDouble;

        if HasGlyph then
        begin
          GlyphPos.Y := FooterRect.Bottom - Glyph.Height - pdDouble;
          Dec(TextPos.Y, Glyph.Height + pdTextToIcon);
        end;

        GlyphPos.X := CenterInRect(ContentRect, Glyph.Width, Glyph.Height).X;
        TextPos.X := CenterInRect(ContentRect, TextSize.cx, TextSize.cy).X;
      end;

    end;

    { Paint Glyph }
    if HasGlyph then
    begin
      if Glyph.Graphic is TBitmap then
      begin
        Bitmap := Glyph.Graphic as TBitmap;
        Bitmap.Transparent := TransparentGlyph;
        DrawBitmap(Canvas, GlyphPos.X, GlyphPos.Y, Bitmap);
      end
      else Canvas.Draw(GlyphPos.X, GlyphPos.Y, Glyph.Graphic);
    end;

    { Paint Text }
    if DisplayMode <> dmImageOnly then
    begin
      case Orientation of
        orHorizontal: CaptionRect := Rect(TextPos.X, FooterRect.Top, FooterRect.Right, FooterRect.Bottom);

        { Note: There is a bug with word-wrap
                & vert text. }
        orVertical: CaptionRect := Rect(TextPos.X, FooterRect.Top, TextPos.X + TextSize.cy + pdStandard, TextPos.Y);
      end;

      case Orientation of
        orHorizontal: DrawTextRect(Canvas, CaptionRect, taLeftJustify, taVerticalCenter, S, WrapKind);
        orVertical: DrawVertTextRect(Canvas, CaptionRect, taLeftJustify, taAlignBottom, S, WrapKind);
      end;
    end;

  end; { with }
end;

procedure TNxNativeGridPartStylePaint.PaintHeader(HeaderRect: TRect; State: TNxButtonState);
begin
  { Background, provided by Style (i.e. Modern or Native) }
  if doBackground in Header.DrawingOptions then
  begin
    PaintHeaderBackground(HeaderRect, State);
  end;

  { Paint Caption, Glyph & Sorting Arrow }
  if doContent in Header.DrawingOptions then
  begin
    PaintHeaderContent(GetHeaderContentRect(HeaderRect), State);
  end;
end;

procedure TNxNativeGridPartStylePaint.PaintHeaderBackground(HeaderRect: TRect; State: TNxButtonState);
begin
  if CanStyle(soVCLStyles)
    then PaintVCLStyledHeader(HeaderRect, State)
  else
    if CanStyle(soNativeStyles)
      then PaintNativeStyledHeader(HeaderRect, State)
    else
      PaintClassicHeader(HeaderRect, State);
end;

procedure TNxNativeGridPartStylePaint.PaintHeaderButton(ButtonRect: TRect; State: TNxButtonState);
begin
  TNxDropButtonStyledView6.Paint(Canvas, Control.Handle, ButtonRect, State, StyleOptions);
end;

procedure TNxNativeGridPartStylePaint.PaintHeaderContent(HeaderRect: TRect;
  State: TNxButtonState);
var
  CaptionRect, ContentRect: TRect;
  TextSize, GlyphSize, ContentSize: TSize;
  ArrowPos, GlyphPos, TextPos: TPoint;
  WrapKind: TNxWrapKind;
  S: WideString;
  HasGlyph, HasText: Boolean;
  Bitmap: TBitmap;
  LongCaptionSpace: Integer;
begin
  { Init. vars }
  WrapKind := wkNone;

  with Column.Header do
  begin
    HasGlyph := ((DisplayMode = dmImageOnly) or (DisplayMode = dmTextAndImage))
      and Assigned(Glyph)
      and Assigned(Glyph.Graphic)
      and not Glyph.Graphic.Empty;

    HasText := (DisplayMode = dmTextOnly) or (DisplayMode = dmTextAndImage);

    { NOTE: Delphi Styles bug-fix }
    Canvas.Font.Color := 0;

    Canvas.Font.Assign(Font);
    Canvas.Font.Color := GetHeaderTextColor(State);

    { Text }
    S := TNxPaintStyle6.TransformText(Caption, TextTransform);

    { Default }
    Unset(TextSize);
    Unset(GlyphSize);
    Unset(ContentSize);

    LongCaptionSpace := RectWidth(HeaderRect);

    case Alignment of
      taLeftJustify, taRightJustify: Dec(LongCaptionSpace, pdDouble);
    end;

    if HasGlyph then
    begin
      GlyphSize := Size(Glyph.Width, Glyph.Height);

      { Shrink Caption space a bit }
      Dec(LongCaptionSpace, GlyphSize.cx + pdTextToIcon);
    end;

    { Has Text? }
    if HasText then
    begin
      { Multiline? }
      WrapKind := wkEllipsis;
      if MultiLine then WrapKind := wkWordWrap;

      { Measure }
      TextSize := GetTextSize(Canvas.Handle, HeaderRect, S, WrapKind);

      { Caption to Short Caption? }
      if (Orientation = orHorizontal)
        and (TextSize.cx > LongCaptionSpace)
        and (ShortCaption <> '') then
      begin
        S := ShortCaption;
        TextSize := GetTextSize(Canvas.Handle, HeaderRect, S, WrapKind);
      end;

      ContentSize := TextSize;
    end;

    if Orientation = orVertical then
      TextSize := Rotate(TextSize);

    { Incl. Padding }
    if (TextSize.cx > 0) and HasGlyph then
    begin
      Inc(TextSize.cx, pdTextToIcon);
    end;

    case Orientation of
      orHorizontal: ContentSize := Size(TextSize.cx + GlyphSize.cx,
        Max(TextSize.cy, GlyphSize.cy));
      orVertical: ContentSize := Max(TextSize, GlyphSize);
    end;

    ContentRect := Bounds(HeaderRect.Left, HeaderRect.Top,
      ContentSize.cx, HeaderRect.Bottom - HeaderRect.Top);

    { Shift content TRect }
    case Alignment of
      taLeftJustify: OffsetRect(ContentRect, pdDouble, 0);
      taRightJustify:
      begin
        OffsetRect(ContentRect, RectWidth(HeaderRect) - ContentSize.cx - pdDouble, 0);

        { Arrow space }
        if Column.Sorted and not HideArrow
          then OffsetRect(ContentRect, -(spArrowDistance + 12), 0);
      end;
      Classes.taCenter: OffsetRect(ContentRect, RectWidth(HeaderRect) div 2 - ContentSize.cx div 2, 0);
    end;

    { Set Glyph & Text positions }
    case Orientation of
      orHorizontal:
      begin

        TextPos.X := ContentRect.Left;

        if HasGlyph then
        begin
          GlyphPos.X := ContentRect.Left;
          GlyphPos.Y := CenterInRect(ContentRect, Glyph.Width, Glyph.Height).Y;
          Inc(TextPos.X, Glyph.Width + pdTextToIcon);
        end;

        TextPos.Y := CenterInRect(ContentRect, TextSize.cx, TextSize.cy).Y;

      end;

      orVertical:
      begin
        TextPos.Y := HeaderRect.Bottom - pdDouble;

        if HasGlyph then
        begin
          GlyphPos.Y := HeaderRect.Bottom - Glyph.Height - pdDouble;
          Dec(TextPos.Y, Glyph.Height + pdTextToIcon);
        end;

        GlyphPos.X := CenterInRect(ContentRect, Glyph.Width, Glyph.Height).X;
        TextPos.X := CenterInRect(ContentRect, TextSize.cx, TextSize.cy).X;
      end;

    end;

    { Paint Glyph }
    if HasGlyph then
    begin
      if Glyph.Graphic is TBitmap then
      begin
        Bitmap := Glyph.Graphic as TBitmap;
        Bitmap.Transparent := TransparentGlyph;
        DrawBitmap(Canvas, GlyphPos.X, GlyphPos.Y, Bitmap);

      end else Canvas.Draw(GlyphPos.X, GlyphPos.Y, Glyph.Graphic);
    end;

    { Paint Text }
    if HasText then
    begin
      case Orientation of
        orHorizontal: CaptionRect := Rect(TextPos.X, HeaderRect.Top, ContentRect.Right, HeaderRect.Bottom);

        { Note: There is a bug with word-wrap
                & vert text. }
        orVertical: CaptionRect := Rect(TextPos.X, HeaderRect.Top, TextPos.X + TextSize.cy + pdDouble, TextPos.Y);
      end;

      case Orientation of
        orHorizontal: DrawTextRect(Canvas, CaptionRect, Column.Header.Alignment, taVerticalCenter, S, WrapKind);
        orVertical: DrawVertTextRect(Canvas, CaptionRect, taLeftJustify, taAlignBottom, S, WrapKind);
      end;
    end;

  end; { with }

  { Show Arrow }
  if Column.Sorted then
  begin
    ArrowPos.Y := HeaderRect.Top + (HeaderRect.Bottom - HeaderRect.Top) div 2 - Pred(ArrowSize.cy) div 2 - 1;
    ArrowPos.X := TextPos.X + TextSize.cx + spArrowDistance;

    if (ArrowPos.X + Succ(ArrowSize.cx) < HeaderRect.Right)
      and not Column.Header.HideArrow then
        DrawSortIndicator(ArrowPos, Column.SortKind);
  end;
end;

procedure TNxNativeGridPartStylePaint.PaintInactiveHeader(HeaderRect: TRect);
begin
  Canvas.Brush.Color := Color;
  TNxHeaderStyle6.PaintInactive(Canvas, Control.Handle, HeaderRect, StyleOptions);
end;

procedure TNxNativeGridPartStylePaint.PaintIndicator(IndicatorRect: TRect; Location: TNxIndicatorLocation; Selected,
  Highlighted: Boolean);
var
  ArrowColor: TColor;
  State: TNxButtonState;
  Pos: TPoint;
begin
  case Location of
    ilHeader, ilInsertRow:
    begin
      if IsStyled then
      begin
        TNxHeaderStyle6.Paint(Canvas, Control.Handle, IndicatorRect, [], StyleOptions);
      end else
      begin
        Frame3D(Canvas, IndicatorRect, clBtnHighlight, clBtnShadow, 1);
        Canvas.Brush.Color := clBtnFace;
        Canvas.FillRect(IndicatorRect);
      end;
    end;

    ilRow:
    begin
      State := [];
      if Selected then Include(State, bsSelected);
      if Selected then Include(State, bsHover);
      if IsStyled then
      begin
        TNxHeaderStyle6.Paint(Canvas, Control.Handle, IndicatorRect, State, StyleOptions);
      end else
      begin
        Frame3D(Canvas, IndicatorRect, clBtnHighlight, clBtnShadow, 1);
        Canvas.Brush.Color := clBtnFace;
        Canvas.FillRect(IndicatorRect);
      end;

      { Selected Row }
      if Selected then
        with Canvas do
        begin
          Font.Color := clWindowText;

          { Actual or Styled Color? }
          ArrowColor := GetHeaderTextColor([bsSelected]);

          Pen.Color := ArrowColor;
          Brush.Color := ArrowColor;

          { Center }
          Pos := PosInRect(Succ(ArrowSize.cy), Succ(ArrowSize.cx), IndicatorRect, Classes.taCenter, taVerticalCenter);

          { Draw Arrow }
          Polygon([
            Point(Pos.X, Pos.Y),
            Point(Pos.X + ArrowSize.cy, Pos.Y + ArrowSize.cy),
            Point(Pos.X, Pos.Y + ArrowSize.cx)
          ]);
        end;
      end;
  end;
end;

procedure TNxNativeGridPartStylePaint.PaintNativeStyledHeader(HeaderRect: TRect; State: TNxButtonState);
begin
  TNxHeaderStyle6.Paint(Canvas, Control.Handle, HeaderRect, State, [soNativeStyles]);
end;

procedure TNxNativeGridPartStylePaint.PaintVCLStyledHeader(HeaderRect: TRect; State: TNxButtonState);
begin
  TNxHeaderStyle6.Paint(Canvas, Control.Handle, HeaderRect, State, [soVCLStyles]);
end;

procedure TNxNativeGridPartStylePaint.SetColumn(const Value: TNxColumn6);
begin
  FColumn := Value;
end;

procedure TNxNativeGridPartStylePaint.SetLocation(const Value: TNxColumnLocation);
begin
  FLocation := Value;
end;

{ TNxModernGridPartStylePaint }

procedure TNxModernGridPartStylePaint.PaintHeaderBackground(HeaderRect: TRect; State: TNxButtonState);
var
  InRect: TRect;
begin
  InRect := HeaderRect;
  Dec(InRect.Right, 1);

  with Canvas, HeaderRect do
  begin
    Brush.Color := clWindow;// Column.Header.Color;

    if bsPressed in State then
      Brush.Color := $00f8f5f2;

    FillRect(InRect);

    Brush.Color := ColorOf(seWindowFrame);
    Pen.Color := Brush.Color;

    if Self.Location = clAlone then
    begin
      FrameRect(HeaderRect);
//      Polyline([Point(Left, Top), Point(Right, Top)]);
//      Polyline([Point(Left, Bottom - 1), Point(Right, Bottom - 1)]);
//      Polyline([Point(Right - 1, Top + 1), Point(Right - 1, Bottom - 1)]);
    end else
    begin
      Polyline([Point(Left, Top), Point(Right, Top)]);
      Polyline([Point(Left, Bottom - 1), Point(Right, Bottom - 1)]);

      if Self.Location = clRightSide
        then Polyline([Point(Right - 1, Top + 1), Point(Right - 1, Bottom - 1)]) else
      begin
        Polyline([Point(Right - 1, Top + 3), Point(Right - 1, Bottom - 3)]);

        Pixels[Right - 1, Top + 1] := clWhite;
        Pixels[Right - 1, Top + 2] := clWhite;
        Pixels[Right - 1, Bottom - 2] := clWhite;
        Pixels[Right - 1, Bottom - 3] := clWhite;
      end;
    end;
  end;
end;

procedure TNxModernGridPartStylePaint.PaintHeaderButton(ButtonRect: TRect; State: TNxButtonState);
var
  Position: TPoint;
begin
  with Canvas do
  begin
    Brush.Color := clNone;

    if bsHover in State then
    begin
      Brush.Color := ColorOf(seBtnFace);
    end;

    if bsPressed in State then
    begin
      Brush.Color := ColorOf(seBtnFacePressed);
    end;

    if Brush.Color <> clNone
      then FillRect(ButtonRect);

    { Paint arrow }
    Position := PosInRect(8, 6, ButtonRect, Classes.taCenter, taVerticalCenter);

    Brush.Color := clGray;
    Pen.Color := Brush.Color;

    with Position do
      Polygon([
        Point(X, Y),
        Point(X + 3, Y + 3),
        Point(X + 6, Y + 0),
        Point(X + 6, Y + 2),
        Point(X + 3, Y + 5),
        Point(X + 0, Y + 2),
        Point(X + 0, Y + 0)
      ]);
  end;
end;

procedure TNxModernGridPartStylePaint.PaintInactiveHeader(HeaderRect: TRect);
begin
  with Canvas do
  begin
    Brush.Color := Color;
    FillRect(HeaderRect);
  end;
end;

procedure TNxModernGridPartStylePaint.PaintIndicator(IndicatorRect: TRect; Location: TNxIndicatorLocation; Selected,
  Highlighted: Boolean);
var
  Pos: TPoint;
begin
  case Location of
    ilHeader:
      with Canvas do
      begin
        Brush.Color := clWindow;
        FillRect(IndicatorRect);

        Brush.Color := ColorOf(seWindowFrame);
        FrameRect(IndicatorRect);
      end;
    ilInsertRow:
      with Canvas do
      begin
        Brush.Color := clWindow;
        FillRect(IndicatorRect);

        Pen.Color := ColorOf(seWindowFrame);

        Polyline([
          IndicatorRect.TopLeft,
          Point(IndicatorRect.Left, Pred(IndicatorRect.Bottom)),
          Point(Pred(IndicatorRect.Right), Pred(IndicatorRect.Bottom)),
          Point(Pred(IndicatorRect.Right), Pred(IndicatorRect.Top))
        ]);
      end;
    ilRow:
      with Canvas do
      begin
        Brush.Color := clWindow;

        if Highlighted then Brush.Color := ColorOf(seBtnFaceChecked);


        FillRect(IndicatorRect);

        Pen.Color := ColorOf(seWindowFrame);

        Polyline([
          Point(IndicatorRect.Left, IndicatorRect.Top),
          Point(IndicatorRect.Left, IndicatorRect.Bottom)
        ]);

        Polyline([
          Point(Pred(IndicatorRect.Right), IndicatorRect.Top),
          Point(Pred(IndicatorRect.Right), IndicatorRect.Bottom)
        ]);

        Polyline([
          Point(IndicatorRect.Left + 2, Pred(IndicatorRect.Bottom)),
          Point(IndicatorRect.Right - 2, Pred(IndicatorRect.Bottom))
        ]);

        { Selected Row }
        if Selected then
          with Canvas do
          begin
            Pen.Color := clGray;
            Brush.Color := clGray;

            { Center }
            Pos := PosInRect(Succ(ArrowSize.cy), Succ(ArrowSize.cx), IndicatorRect, Classes.taCenter, taVerticalCenter);

            { Draw Arrow }
            Polygon([
              Point(Pos.X, Pos.Y),
              Point(Pos.X + ArrowSize.cy, Pos.Y + ArrowSize.cy),
              Point(Pos.X, Pos.Y + ArrowSize.cx)
            ]);
          end;
      end;
  end;
end;

procedure TNxModernGridPartStylePaint.PaintProgressBar(BarRect: TRect);
begin
  with Canvas do
  begin
    Brush.Color := ColorOf(seDivider);
    FrameRect(BarRect);
  end;
end;

procedure TNxModernGridPartStylePaint.PaintProgressChunk(ChunkRect: TRect);
begin
  with Canvas do
  begin
    Brush.Color := ColorOf(seMenu);
    InflateRect(ChunkRect, -1, -1);
    FillRect(ChunkRect);
  end;
end;

procedure TNxModernGridPartStylePaint.PaintToolButton(ButtonRect: TRect; State: TNxButtonState);
begin
  with Canvas do
    if State <> [] then
    begin
      { Default }
      Brush.Color := ColorOf(seBtnFace);

      if bsPressed in State then
      begin
        if bsHover in State
          then Brush.Color := ColorOf(seBtnFacePressed)
          else Exit;
      end
      else if bsChecked in State then
        if bsHover in State
          then Brush.Color := ColorOf(seBtnFace)
          else Brush.Color := ColorOf(seBtnFaceChecked);

      FillRect(ButtonRect);
    end;
end;

{ TNxUserDefinedStylePaint }

constructor TNxUserDefinedStylePaint.Create(AOwner: TComponent);
begin
  inherited;
  FButtonColor := clBtnFace;
  FButtonHoverColor := cl3DLight;
  FButtonPressedColor := cl3DLight;
  FHeaderHoverColor := cl3DLight;
  FHeaderPressedColor := cl3DLight;
  FLinesColor := clBtnShadow;
end;

procedure TNxUserDefinedStylePaint.PaintHeaderBackground(HeaderRect: TRect;
  State: TNxButtonState);
var
  InsideRect: TRect;
  BackColor: TColor;
begin
  BackColor := Column.Header.Color;

  InsideRect := HeaderRect;
  Dec(InsideRect.Right, 1);

  with Canvas, HeaderRect do
  begin
    Brush.Color := BackColor;

    if bsHover in State then
      Brush.Color := HeaderHoverColor;

    if bsPressed in State then
      Brush.Color := HeaderPressedColor;

    FillRect(InsideRect);

    Brush.Color := LinesColor;
    Pen.Color := Brush.Color;

    if Self.Location = clAlone then FrameRect(HeaderRect) else
    begin
//      Polyline([Point(Left, Top), Point(Right, Top)]);
      Polyline([Point(Left, Bottom - 1), Point(Right, Bottom - 1)]);

      if Self.Location = clRightSide
        then Polyline([Point(Right - 1, Top), Point(Right - 1, Bottom - 1)]) else
      begin
        Polyline([Point(Right - 1, Top + 2), Point(Right - 1, Bottom - 3)]);

        Pixels[Right - 1, Top] := BackColor;
        Pixels[Right - 1, Top + 1] := BackColor;
        Pixels[Right - 1, Bottom - 2] := BackColor;
        Pixels[Right - 1, Bottom - 3] := BackColor;
      end;
    end;
  end;
end;

procedure TNxUserDefinedStylePaint.PaintInactiveHeader(HeaderRect: TRect);
begin
  Canvas.Brush.Color := Color;
  Canvas.FillRect(HeaderRect);
end;

procedure TNxUserDefinedStylePaint.PaintIndicator(IndicatorRect: TRect; Location: TNxIndicatorLocation; Selected,
  Highlighted: Boolean);
var
  Pos: TPoint;
begin
  case Location of
    ilHeader:
      with Canvas do
      begin
        Pen.Color := clBtnShadow;
        Brush.Color := clBtnFace;
        FillRect(IndicatorRect);
        Polyline([
          Point(IndicatorRect.Right - 1, IndicatorRect.Top - 1),
          Point(IndicatorRect.Right - 1, IndicatorRect.Bottom - 1),
          Point(IndicatorRect.Left - 1, IndicatorRect.Bottom - 1)
        ]);
      end;
    ilInsertRow:
      with Canvas do
      begin
        Brush.Color := clBtnFace;
        FillRect(IndicatorRect);

        Pen.Color := clBtnShadow;

        Polyline([
          Point(IndicatorRect.Right - 1, IndicatorRect.Top - 1),
          Point(IndicatorRect.Right - 1, IndicatorRect.Bottom - 1),
          Point(IndicatorRect.Left - 1, IndicatorRect.Bottom - 1)
        ]);
      end;
    ilRow:
      with Canvas do
      begin
        Brush.Color := clBtnFace;
        if Highlighted then Brush.Color := cl3DLight;

        FillRect(IndicatorRect);

        Pen.Color := clBtnShadow;

        Polyline([
          Point(Pred(IndicatorRect.Right), IndicatorRect.Top),
          Point(Pred(IndicatorRect.Right), IndicatorRect.Bottom)
        ]);

        Polyline([
          Point(IndicatorRect.Left + 2, IndicatorRect.Bottom - 1),
          Point(IndicatorRect.Right - 3, IndicatorRect.Bottom - 1)
        ]);

        { Selected Row }
        if Selected then
          with Canvas do
          begin
            Pen.Color := clGray;
            Brush.Color := Pen.Color;

            { Center }
            Pos := PosInRect(Succ(ArrowSize.cy), Succ(ArrowSize.cx), IndicatorRect, Classes.taCenter, taVerticalCenter);

            { Draw Arrow }
            Polygon([
              Point(Pos.X, Pos.Y),
              Point(Pos.X + ArrowSize.cy, Pos.Y + ArrowSize.cy),
              Point(Pos.X, Pos.Y + ArrowSize.cx)
            ]);
          end;
      end;
  end;
end;

procedure TNxUserDefinedStylePaint.SetButtonColor(const Value: TColor);
begin
  FButtonColor := Value;
end;

procedure TNxUserDefinedStylePaint.SetButtonHoverColor(const Value: TColor);
begin
  FButtonHoverColor := Value;
end;

procedure TNxUserDefinedStylePaint.SetButtonPressedColor(const Value: TColor);
begin
  FButtonPressedColor := Value;
end;

procedure TNxUserDefinedStylePaint.SetHeaderHoverColor(const Value: TColor);
begin
  FHeaderHoverColor := Value;
end;

procedure TNxUserDefinedStylePaint.SetHeaderPressedColor(const Value: TColor);
begin
  FHeaderPressedColor := Value;
end;

end.
