//**************************************************************************************************
//                                                                                                  
// Unit Vcl.Styles.DbGrid                                                                           
// unit for the VCL Styles Utils                                                                    
// https://github.com/RRUZ/vcl-styles-utils/                                                       
//                                                                                                  
// 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/                                                           
//                                                                                                  
// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF   
// ANY KIND, either express or implied. See the License for the specific language governing rights  
// and limitations under the License.                                                               
//                                                                                                  
// The Original Code is Vcl.Styles.DbGrid.pas.                                                      
//                                                                                                  
// The Initial Developer of the Original Code is Rodrigo Ruz V.                                     
// Portions created by Rodrigo Ruz V. are Copyright (C) 2012-2023 Rodrigo Ruz V.                         
// All Rights Reserved.                                                                             
//                                                                                                  
//**************************************************************************************************
unit Vcl.Styles.DbGrid;

interface

uses
  Winapi.Windows,
  Vcl.Grids,
  Vcl.Graphics,
  Vcl.DBGrids;

type
  TDBGrid = class(Vcl.DBGrids.TDBGrid)
  protected
    procedure DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState); override;
  end;

implementation

uses
  Data.DB,
  System.SysUtils,
  System.Classes,
  System.UITypes,
  Vcl.Forms,
  Vcl.Styles,
  Vcl.Themes,
  Vcl.Controls;

type
   TCustomGridClass = class(TCustomGrid);
   TDbGridHelper = class helper for TCustomDBGrid
  private
    function GetTitleOffset: Byte;
    function GetIndicators: TImageList;
    function GetSelRow: Integer;
    procedure SetSelRow(const Value: Integer);
   public
    property TitleOffset: Byte read GetTitleOffset;
    property Indicators: TImageList read GetIndicators;
    property SelRow: Integer read GetSelRow write SetSelRow;
   end;

{ TDbGridHelper }

function TDbGridHelper.GetIndicators: TImageList;
begin
  with Self do
    Result := FIndicators;
end;

function TDbGridHelper.GetSelRow: Integer;
begin
  with Self do
    Result := FSelRow;
end;

function TDbGridHelper.GetTitleOffset: Byte;
begin
  with Self do
    Result := FTitleOffset;
end;

procedure TDbGridHelper.SetSelRow(const Value: Integer);
begin
  with Self do
    FSelRow := Value;
end;

procedure _WriteText(ACanvas: TCanvas; ARect: TRect; DX, DY: Integer; const AText: string; Alignment: TAlignment; ARightToLeft: Boolean);
var
  X: Integer;
begin
  if (ACanvas.CanvasOrientation = coRightToLeft) and (not ARightToLeft) then
    ChangeBiDiModeAlignment(Alignment);
  case Alignment of
    taLeftJustify: X := ARect.Left + DX;
    taRightJustify: X := ARect.Right - ACanvas.TextWidth(AText) - 3;
  else
    X := ARect.Left + (ARect.Right - ARect.Left) shr 1 - (ACanvas.TextWidth(AText) shr 1);
  end;
  ACanvas.TextRect(ARect, X, ARect.Top + DY, AText);
end;


{ TDBGrid }

procedure TDBGrid.DrawCell(ACol, ARow: Integer; ARect: TRect; AState: TGridDrawState);
var
  OldActive: Integer;
  Indicator: TThemedGrid;
  Value: string;
  CurrentColumn: TColumn;
  MultiSelected: Boolean;
  X: Integer;
  LStyleServices: TCustomStyleServices;
  DeltaX: Byte;
  Index: Integer;
begin
  LStyleServices := StyleServices;
  if not TStyleManager.IsCustomStyleActive or (ARow-TitleOffset<0) then
  begin
    inherited DrawCell(ACol, ARow, ARect, AState);
    exit;
  end;

  if csLoading in ComponentState then
  begin
    Canvas.Brush.Color := LStyleServices.GetStyleColor(scGrid);
    Canvas.FillRect(ARect);
    Exit;
  end;

  Dec(ARow, TitleOffset);
  Dec(ACol, IndicatorOffset);

  if (gdFixed in AState) and ([dgRowLines, dgColLines] * Options =
    [dgRowLines, dgColLines]) then
  begin
    Winapi.Windows.InflateRect(ARect, -1, -1);
    DeltaX := 1;
  end
  else
    DeltaX := 2;

  if (gdFixed in AState) and (ACol < 0) then
  begin
    DrawCellBackground(ARect, FixedColor, AState, ACol, ARow);
    if Assigned(DataLink) and DataLink.Active  then
    begin
      MultiSelected := False;

      if ARow >= 0 then
      begin
        OldActive := DataLink.ActiveRecord;
        try
          DataLink.ActiveRecord := ARow;
          MultiSelected :=  (dgMultiSelect in Options) and Datalink.Active and  SelectedRows.Find(Datalink.Datasource.Dataset.Bookmark, Index);;
        finally
          DataLink.ActiveRecord := OldActive;
        end;
      end;

      if (ARow = DataLink.ActiveRecord) or MultiSelected then
      begin
        Indicator := tgIndicatorArrow;
        if DataLink.DataSet <> nil then
          case DataLink.DataSet.State of
            dsEdit: Indicator := tgIndicatorEdit;
            dsInsert: Indicator := tgIndicatorInsert;
            dsBrowse:
              if MultiSelected then
                if (ARow <> DataLink.ActiveRecord) then
                  Indicator := tgIndicatorMultiDot
                else
                  Indicator := tgIndicatorMultiArrow;
          end;
        Indicators.BkColor := FixedColor;
        X := ARect.Right - Indicators.Width - DeltaX;
        if Canvas.CanvasOrientation = coRightToLeft then
          Inc(X);

        if LStyleServices.Enabled and not LStyleServices.IsSystemStyle then
          LStyleServices.DrawElement(Canvas.Handle, LStyleServices.GetElementDetails(Indicator), ARect)
        else
          Indicators.Draw(Canvas, X, (ARect.Top + ARect.Bottom - Indicators.Height) shr 1, Integer(Indicator) - Integer(tgIndicatorArrow), True);

        if ARow = Datalink.ActiveRecord then
          SelRow := ARow + TitleOffset;
      end;
    end;
  end
  else
  with Canvas do
  begin
    CurrentColumn := Columns[ACol];
    if not CurrentColumn.Showing then Exit;
    if not (gdFixed in AState) then
    begin
      Font := CurrentColumn.Font;
      Brush.Color := CurrentColumn.Color;

      if (Brush.Color=LStyleServices.GetStyleColor(scGrid)) then
      begin
        Font.Color := LStyleServices.GetStyleFontColor(sfGridItemNormal);
        Brush.Color := LStyleServices.GetStyleColor(scGrid);
      end;

    end;

    if (DataLink = nil) or not DataLink.Active then
      FillRect(ARect)
    else
    begin
      Value := '';
      OldActive := DataLink.ActiveRecord;
      try
        DataLink.ActiveRecord := ARow;
        if Assigned(CurrentColumn.Field) then
          Value := CurrentColumn.Field.DisplayText;
        if HighlightCell(ACol, ARow, Value, AState) and DefaultDrawing then
          DrawCellHighlight(ARect, AState, ACol, ARow);
        if not Enabled then
          Font.Color := clGrayText;

        if DefaultDrawing then
          _WriteText(Canvas, ARect, 3, 2, Value, CurrentColumn.Alignment, UseRightToLeftAlignmentForField(CurrentColumn.Field, CurrentColumn.Alignment));

        if Columns.State = csDefault then
          DrawDataCell(ARect, CurrentColumn.Field, AState);
        DrawColumnCell(ARect, ACol, CurrentColumn, AState);
      finally
        DataLink.ActiveRecord := OldActive;
      end;
      Canvas.Brush.Style := bsSolid;

      if DefaultDrawing and (gdSelected in AState) and ((dgAlwaysShowSelection in Options) or Focused)
        and not (csDesigning in ComponentState) and not (dgRowSelect in Options)
        and (UpdateLock = 0) and (ValidParentForm(Self).ActiveControl = Self) and
      (FInternalDrawingStyle = gdsThemed) and (Win32MajorVersion >= 6) then
        Winapi.Windows.InflateRect(ARect, -1, -1);

    end;
  end;

  if (gdFixed in AState) and ([dgRowLines, dgColLines] * Options =
     [dgRowLines, dgColLines]) and (FInternalDrawingStyle = gdsClassic) and
     not (gdPressed in AState) then
    Winapi.Windows.InflateRect(ARect, 1, 1);
end;


end.
