unit uBafPdfModule2;

// this code is under the BAF fair use license (BFUL) - https://bafbal.de/index.php?title=Bful
// module for creating PDFs; needs Skia4Delphi
// https://bafbal.de/index.php?title=Modul_PDF

interface

{$DEFINE with_zint}


uses System.Math, System.SysUtils, System.Classes, uBafTypes, uBafInterpreter,
  System.Contnrs, System.StrUtils, System.UiTypes, FMX.Graphics,

  Skia, FMX.Skia,

  {$IFDEF with_zint}
  zint, zint_helper, zint_render_fmx_bmp,
  {$ENDIF}

  FMX.Dialogs, uBafPage, System.Types, DB, dmMain, FMX.Types, FMX.Forms;

type
  TBafPdfMargins = record
    Left: single;
    Right: single;
  end;

  TBafPdfGridColumn = class
    Index: integer;
    Page: integer;
    Left: single;
    Right: single;
  end;

  TBafPdfModule = class(TBafInterpreterCustomModule)
  protected
    FCanvas: ISkCanvas;
    FDocument: ISkDocument;
    FDocumentFileName: string;
    FTemporaryFileName: string;
    FDocumentStream: TStream;
    FLandscape: boolean;
    FFont: ISkFont;
    FFontPaint: ISkPaint;
    FDrawPaint: ISkPaint;
    FPageSize: TSizeF;
    FPage: integer;
    FY: single;
    FLineHeight: single;
    FZoom: single;
    FNow: string;
    FColCount, FColNum: integer;  // FColNum is 0 relative
    FColYPos: single;
    FColMargins: array[0..9] of TBafPdfMargins;
    FLineGroup: TStringList;
    FGridColWidths: array[1..20] of single;
    FGridColCount: integer;
    FGridDefaultRowHeight: single;
    FGridLeft, FGridWidth: single;
    FGridMarginBottom: single;
    FGridMarginLeft, FGridMarginRight, FGridMarginTop: single;
    FGridDrawLines: boolean;
    procedure PdfStart(AIntern: boolean = false; ALandscape: boolean = false; AFileName: string = '');
    procedure PdfStop(ADoOpen: boolean);
    procedure PdfAddPage;
    procedure PdfAddCol;
    procedure PdfLine(ALineFeed: boolean);
    procedure PdfMultiline;
    procedure PdfMultilineBB2;
    procedure PdfFont;
    procedure PdfSetY;
    procedure PdfInsertPic;
    procedure PdfDrawLine;
    procedure PdfDrawRectangle;
    procedure PdfExecSub;
    procedure PdfCheckNewLine;
    procedure PdfColfDef;
    procedure PdfColfClear;
    procedure PdfDrawDef;
    procedure PdfGridDef;
    procedure PdfGridRow;
    procedure PdfGridEnd;
    procedure PdfGridHorzLine;
    procedure PdfGridVertLine(AXPos, AHeight: single);
    {$IFDEF with_zint}
    procedure PdfCreateBarcode;
    {$ENDIF}
    procedure PdfBus;
    procedure PdfVBus;
    procedure PdfVBusNamen;
    procedure PdfMaxSizeText;
  protected
    FGrid: TBafSimpleGrid;
    FColumns: TObjectList;
    FPageWidthUse, FPageScale: single;
    FPageMarginLeft, FPageMarginTop, FPageMarginRight, FPageMarginBottom: single;
    FPagesPerRow: integer;
    FPdfFileName: string;
    function OpenFileDialog(var AFileName: string): boolean;
    function ExportSegment(ASegment: TBafPageSegment): boolean;
    procedure ExportGrid(AGrid: TBafSimpleGrid);
    procedure MakeColumns;
    procedure PrintHeader(APage, ARow: integer);
    procedure PrintRows(APage: integer; AStart: integer; var ALast: integer);
    procedure InitPage;
    procedure PrintCell(ACell: TBafSgCell; ACol: integer;
        APdfGridColumn: TBafPdfGridColumn);
  protected
    function CalcTextLeft(AText: string; AWidth: single; AAlignment: TBafAlignment): single;
    procedure CheckNewLine(AMarginBottom: single);
  public
    constructor Create; override;
    destructor Destroy; override;
    function InterpretLine(AExecInter: TBafCustomInterpreter): boolean; override;
    function ReplaceFunction(ACommand: string; AParams: TStrings; var AResult: string): boolean; override;
    procedure ExportSegmentPdf(ASegment: TObject); override;
    procedure ExportPagePdf(APage: TObject); override;
  end;


implementation

{ TBafPdfModule }

uses uOsStuff, uBafTranslationModule;

function TBafPdfModule.CalcTextLeft(AText: string; AWidth: single; AAlignment: TBafAlignment): single;
// Calcs start position of text regarding to alignment
var
  p: integer;
  LTextWidth: single;
begin
  result := 0;
  case AAlignment of
    taLeftJustify, taExplicitLeft: result := 0;
    taRightJustify: begin
      LTextWidth := FFont.MeasureText(AText, FFontPaint);
      result := AWidth - 2 - LTextWidth;
    end;
    taCenter: begin
      LTextWidth := FFont.MeasureText(AText, FFontPaint);
      result := (AWidth - LTextWidth) / 2;
    end;
    taDecimal2: begin
      p := Pos(',', AText);
      if p > 0 then
        AText := copy(AText, 1, p - 1);
      AText := AText + ',00';
      LTextWidth := FFont.MeasureText(AText, FFontPaint);
      result := AWidth - 2 - LTextWidth;
    end;
    taDecimal4: begin
      p := Pos(',', AText);
      if p > 0 then
        AText := copy(AText, 1, p - 1);
      AText := AText + ',0000';
      LTextWidth := FFont.MeasureText(AText, FFontPaint);
      result := AWidth - 2 - LTextWidth;
    end;
  end; // case
  result := result + FColMargins[FColNum].Left;
end;

procedure TBafPdfModule.CheckNewLine(AMarginBottom: single);
begin
  FY := FY + FLineHeight;
  if FY > (FPageSize.Height - AMarginBottom) then
    PdfAddCol;
end;

constructor TBafPdfModule.Create;
begin
  inherited;
  FLineGroup := TStringList.Create;
end;

destructor TBafPdfModule.Destroy;
begin
  FreeAndNil(FLineGroup);
  inherited;
end;

procedure TBafPdfModule.ExportGrid(AGrid: TBafSimpleGrid);
var
  LRow, LLast, LPage: integer;
begin
  FGrid := AGrid;
  FColumns := TObjectList.Create(true);
  try
    InitPage;
    MakeColumns;
    LRow := 0;
    while LRow < AGrid.RowCount(rtData) do begin
      for LPage := 1 to FPagesPerRow do begin
        PrintHeader(LPage, LRow);
        PrintRows(LPage, LRow, LLast);
      end;
      LRow := LLast + 1;
    end;
  finally
    FreeAndNil(FColumns);
  end;
end;

procedure TBafPdfModule.ExportPagePdf(APage: TObject);
var
  LPage: TBafPage;
begin
  if OpenFileDialog(FPdfFileName) then begin
    LPage := (APage as TBafPage);
    LPage.AllSegFunction(ExportSegment);
    PdfStop(true);
  end; // if OpenFileDialog
end;

procedure TBafPdfModule.ExportSegmentPdf(ASegment: TObject);
begin
  if OpenFileDialog(FPdfFileName) then begin
    ExportSegment(ASegment as TBafPageSegment);
    PdfStop(true);
  end; // if OpenFileDialog
end;

function TBafPdfModule.ExportSegment(ASegment: TBafPageSegment): boolean;

  procedure lokAddPage;
  begin
    FLandscape := FindParamBooleanReplaced(ASegment.LineP, 'pal', false);
    if FFont = nil then
      PdfStart(true, FLandscape, FPdfFileName)
    else
      PdfAddPage;
  end; // procedure lokAddPage

begin
  result := true;
  if ASegment.PdfCommand = '' then begin
    case ASegment.SegmentType of
      stValueList, stGrid, stXGrid, stXXGrid: begin
        lokAddPage;
        ExportGrid(ASegment.Grid);
      end;
    end;
  end
  else begin
    lokAddPage;
    TBafInterpreterLevel.ExecInNewLevel(ASegment.PdfCommand, FExecInter, FInter);
  end;
end;

function TBafPdfModule.ReplaceFunction(ACommand: string; AParams: TStrings;
    var AResult: string): boolean;
begin
  inherited;
  result := true;
  if ACommand = '$PDF_PAGE' then AResult := IntToStr(FPage)
  else if ACommand = '$PDF_YMM' then AResult := FormatFloat('0.00',
      FY / System.Math.Max(FZoom, 0.001))

  else result := false;
end;

procedure TBafPdfModule.PdfAddCol;
begin
  if FindParamBooleanReplaced('cnd', true) then begin
    inc(FColNum);
    if FColNum >= FColCount then
      PdfAddPage;
    FY := FColYPos;
  end;
end;

procedure TBafPdfModule.PdfAddPage;
begin
  if FindParamBooleanReplaced('cnd', true) then begin
    if Assigned(FCanvas) then begin
      FDocument.EndPage;
      FCanvas := nil;
    end;
    if FLandscape then
      FPageSize := TSizeF.Create(842, 595)
    else
      FPageSize := TSizeF.Create(595, 842);
    FCanvas := FDocument.BeginPage(FPageSize.Width, FPageSize.Height);
    inc(FPage);
    FColNum := 0;
    if FLandscape then
      FZoom := FPageSize.Width / 297
    else
      FZoom := FPageSize.Width / 210;
  //  FY := (FPageSize.Height / FZoom) - 15;
    FY := 15 * FZoom;
    FColYPos := FY;
  end;
end;

function PreisListenSort(List: TStringList; Index1, Index2: Integer): Integer;
var
  LPreis1, LPreis2: currency;
begin
  LPreis1 := StrToCurrDef(List[Index1], 0) * 100;
  LPreis2 := StrToCurrDef(List[Index2], 0) * 100;
  result := round(LPreis2 - LPreis1);
end;

procedure TBafPdfModule.PdfBus;
const
  SITZ = 100;
  ZWI = 20;


type
  TBusPlatz = record
    platz: string[3];
    status: Char;
    ausrichtung: Char;
    preis: currency;
  end;

var
  LBus: array[0..17, 0..4] of TBusPlatz;
  LRowCount: integer;
  LPlatz: TBusPlatz;
  LPreisListe: TStringList;
  LFontSize: integer;
  LFmtString: string;
  LScale: single;
  LFillPaint: ISkPaint;
  LEinstiegPaint: ISkPaint;

  LLeft, LRight, LDrawWidth: single;


  procedure lokText(x1, y1, ASize: single; ABold: boolean; AText: string);
  begin
    FFont.Size := ASize * LScale;
    FFont.Embolden := ABold;
    FCanvas.DrawSimpleText(AText, LLeft + x1 * LScale, FY + y1 * LScale, FFont, FFontPaint);
  end; // procedure lokText

  procedure lokBusSitz(AReihe, ASpalte: integer; ASitzX, ASitzY: single;
      AZeile2: string; ASize: integer; ABold: boolean);
  begin
    case LPlatz.ausrichtung of
      'V': begin
        FCanvas.DrawRect(TRectF.Create(LLeft + (ASitzX - 15) * LScale, FY + ASitzY * LScale,
            LLeft + (ASitzX - SITZ) * LScale, FY + (ASitzY + SITZ) * LScale), LFillPaint);
        FCanvas.DrawRect(TRectF.Create(LLeft + (ASitzX - 15) * LScale, FY + ASitzY * LScale,
            LLeft + (ASitzX - SITZ) * LScale, FY + (ASitzY + SITZ) * LScale), FDrawPaint);
        FCanvas.DrawLine(LLeft + (ASitzX - SITZ + 15) * LScale, FY + ASitzY * LScale,
            LLeft + (ASitzX - SITZ + 15) * LScale, FY + (ASitzY + SITZ - 1) * LScale, FDrawPaint);
        lokText(ASitzX - SITZ + 20, ASitzY + 40, LFontSize, ABold, LPlatz.platz);
        lokText(ASitzX - SITZ + 20, ASitzY + 85, ASize, ABold, AZeile2);
      end;
      'H': begin
        FCanvas.DrawRect(TRectF.Create(LLeft + (ASitzX) * LScale, FY + ASitzY * LScale,
            LLeft + (ASitzX - SITZ + 15) * LScale, FY + (ASitzY + SITZ) * LScale), LFillPaint);
        FCanvas.DrawRect(TRectF.Create(LLeft + (ASitzX) * LScale, FY + ASitzY * LScale,
            LLeft + (ASitzX - SITZ + 15) * LScale, FY + (ASitzY + SITZ) * LScale), FDrawPaint);
        FCanvas.DrawLine(LLeft + (ASitzX - 15) * LScale, FY + ASitzY * LScale,
            LLeft + (ASitzX - 15) * LScale, FY + (ASitzY + SITZ - 1) * LScale, FDrawPaint);
        lokText(ASitzX - SITZ + 20, ASitzY + 40, LFontSize, ABold, LPlatz.platz);
        lokText(ASitzX - SITZ + 20, ASitzY + 85, ASize, ABold, AZeile2);
      end;
      'L': begin
        FCanvas.DrawRect(TRectF.Create(LLeft + (ASitzX) * LScale, FY + (ASitzY + 15) * LScale,
            LLeft + (ASitzX - SITZ) * LScale, FY + (ASitzY + SITZ) * LScale), LFillPaint);
        FCanvas.DrawRect(TRectF.Create(LLeft + (ASitzX) * LScale, FY + (ASitzY + 15) * LScale,
            LLeft + (ASitzX - SITZ) * LScale, FY + (ASitzY + SITZ) * LScale), FDrawPaint);
        FCanvas.DrawLine(LLeft + (ASitzX) * LScale, FY + (ASitzY + SITZ - 15) * LScale,
            LLeft + (ASitzX - SITZ - 1) * LScale, FY + (ASitzY + SITZ - 15) * LScale, FDrawPaint);
        lokText(ASitzX - SITZ + 15, ASitzY + 45, LFontSize, ABold, LPlatz.platz);
        lokText(ASitzX - SITZ + 15, ASitzY + 75, ASize, ABold, AZeile2);
      end;
      'R': begin
        FCanvas.DrawRect(TRectF.Create(LLeft + (ASitzX) * LScale, FY + (ASitzY) * LScale,
            LLeft + (ASitzX - SITZ) * LScale, FY + (ASitzY + SITZ - 15) * LScale), LFillPaint);
        FCanvas.DrawRect(TRectF.Create(LLeft + (ASitzX) * LScale, FY + (ASitzY) * LScale,
            LLeft + (ASitzX - SITZ) * LScale, FY + (ASitzY + SITZ - 15) * LScale), FDrawPaint);
        FCanvas.DrawLine(LLeft + (ASitzX) * LScale, FY + (ASitzY + 15) * LScale,
            LLeft + (ASitzX - SITZ - 1) * LScale, FY + (ASitzY + 15) * LScale, FDrawPaint);
        lokText(ASitzX - SITZ + 15, ASitzY + 45, LFontSize, ABold, LPlatz.platz);
        lokText(ASitzX - SITZ + 15, ASitzY + 75, ASize, ABold, AZeile2);
      end;
    end;
  end; // procedure lokBusSitz

  procedure lokDouble(ASpalte: integer; ASitzX, ASitzY, ASize: single; AText: string;
      ACombi: boolean = false);
  begin
    if ACombi then begin
      if ASpalte in [0] then begin
        FCanvas.DrawRect(TRectF.Create(LLeft + ASitzX * LScale, FY + (ASitzY + SITZ div 2) * LScale,
            LLeft + (ASitzX - SITZ div 2) * LScale, FY + (ASitzY + SITZ + ZWI + SITZ) * LScale), FDrawPaint);
        lokText(ASitzX - SITZ div 2 + 6, ASitzY + 115 + SITZ div 4, ASize, false, AText);
      end
      else if ASpalte in [3] then begin
        FCanvas.DrawRect(TRectF.Create(LLeft + ASitzX * LScale, FY + ASitzY * LScale,
            LLeft + (ASitzX - SITZ div 2) * LScale, FY + (ASitzY + SITZ + ZWI + SITZ div 2) * LScale), FDrawPaint);
        lokText(ASitzX - SITZ div 2 + 6, ASitzY + 115 - SITZ div 4, ASize, false, AText);
      end;
    end
    else begin
      if ASpalte in [0, 3] then begin
        FCanvas.DrawRect(TRectF.Create(LLeft + ASitzX * LScale, FY + ASitzY * LScale,
            LLeft + (ASitzX - SITZ) * LScale, FY + (ASitzY + SITZ + ZWI + SITZ) * LScale), FDrawPaint);
        lokText(ASitzX - SITZ + 7, ASitzY + 110, ASize, false, AText);
      end;
    end;
  end; // procedure lokDouble

  procedure lokFahrer(ASpalte: integer; ASitzX, ASitzY, ASize: single);
  var
    LHalb: integer;
  begin
    if ASpalte in [0, 3] then begin
      LHalb := (SITZ + ZWI) div 2;
      FCanvas.DrawRect(TRectF.Create(LLeft + ASitzX * LScale, FY + (ASitzY + LHalb) * LScale,
          LLeft + (ASitzX - SITZ) * LScale, FY + (ASitzY + SITZ + LHalb) * LScale), FDrawPaint);
      FCanvas.DrawLine(LLeft + (ASitzX - SITZ + 15) * LScale, FY + (ASitzY + LHalb) * LScale,
          LLeft + (ASitzX - SITZ + 15) * LScale, FY + (ASitzY + SITZ + LHalb - 1) * LScale, FDrawPaint);
      lokText(ASitzX - SITZ + 20, ASitzY + LHalb + 55, ASize, false, 'Fahrer');
    end;
  end; // procedure lokFahrer

  procedure lokEinstieg(ASpalte: integer; ASitzX, ASitzY, ASize: single);
  begin
    if ASpalte = 0 then begin
      FCanvas.DrawRect(TRectF.Create(LLeft + ASitzX * LScale, FY + 3 * LScale,
          LLeft + (ASitzX - SITZ) * LScale, FY + 10 * LScale), LEinstiegPaint);
      lokText(ASitzX - SITZ + 10, 40, ASize, true, 'Einstieg');
    end;
    if ASpalte = 4 then begin
      FCanvas.DrawRect(TRectF.Create(LLeft + ASitzX * LScale, FY + 611 * LScale,
          LLeft + (ASitzX - SITZ) * LScale, FY + 618 * LScale), LEinstiegPaint);
      lokText(ASitzX - SITZ + 10, 600, ASize, true, 'Einstieg');
    end;
  end; // procedure lokEinstieg

  procedure lokUmriss;
  begin
    FCanvas.DrawArc(TRectF.Create(LLeft + 5 * LScale, FY + 5 * LScale,
        LLeft + 25 * LScale, FY + 25 * LScale), 180, 90, false, FDrawPaint);
    FCanvas.DrawLine(LLeft + 15 * LScale, FY + 5 * LScale,
        LLeft + (LDrawWidth - 65) * LScale, FY + 5 * LScale, FDrawPaint);
    FCanvas.DrawArc(TRectF.Create(LLeft + (LDrawWidth - 125) * LScale, FY + 5 * LScale,
        LLeft + (LDrawWidth - 5) * LScale, FY + 125 * LScale), 270, 90, false, FDrawPaint);
    FCanvas.DrawLine(LLeft + (LDrawWidth - 5) * LScale, FY + 65 * LScale,
        LLeft + (LDrawWidth - 5) * LScale, FY + 553 * LScale, FDrawPaint);
    FCanvas.DrawArc(TRectF.Create(LLeft + (LDrawWidth - 125) * LScale, FY + 493 * LScale,
        LLeft + (LDrawWidth - 5) * LScale, FY + 613 * LScale), 0, 90, false, FDrawPaint);
    FCanvas.DrawLine(LLeft + 15 * LScale, FY + 613 * LScale,
        LLeft + (LDrawWidth - 65) * LScale, FY + 613 * LScale, FDrawPaint);
    FCanvas.DrawArc(TRectF.Create(LLeft + 5 * LScale, FY + 593 * LScale,
        LLeft + 25 * LScale, FY + 613 * LScale), 90, 90, false, FDrawPaint);
    FCanvas.DrawLine(LLeft + 5 * LScale, FY + 15 * LScale,
        LLeft + 5 * LScale, FY + 603 * LScale, FDrawPaint);

  end; // procedure lokUmriss

  procedure lokBusSitze;
  var
    LReihe, LSpalte, ix: integer;
    LSitzX, LSitzY, LDrawWidth2: single;
  begin
    LDrawWidth := LRowCount * 120 + 100;
    LDrawWidth2 := Max(LRowCount, 15) * 120 + 100;
    LScale := (FPageSize.Width - LLeft - LRight) / LDrawWidth2;
    FDrawPaint.StrokeWidth := 3 * LScale;
    lokUmriss;
    for LReihe := 0 to LRowCount - 1 do begin
      LSitzX := LDrawWidth - LReihe * (SITZ + ZWI) - SITZ;
      for LSpalte := 0 to 4 do begin
        LSitzY := LSpalte * (SITZ + ZWI) + ZWI;
        LPlatz := LBus[LReihe, LSpalte];
        ix := LPreisListe.IndexOf(FormatFloat('0.00', LPlatz.preis));
        if ix = -1 then
          ix := 0;
        LFillPaint.Color := TAlphaColor(LPreisListe.Objects[ix]);
        case LPlatz.status of
          'G': lokBusSitz(LReihe, LSpalte, LSitzX, LSitzY,             // gesperrt
              '-', LFontSize, false);
          'R': lokBusSitz(LReihe, LSpalte, LSitzX, LSitzY,
              IfThen(LFmtString = '', '', FormatFloat(LFmtString, LPlatz.preis)),
              LFontSize, true);
          'L': lokBusSitz(LReihe, LSpalte, LSitzX, LSitzY, 'R-Leiter', 10, true);
          'Z': lokBusSitz(LReihe, LSpalte, LSitzX, LSitzY, '2. Fahrer', 10, true);
          'T': lokDouble(LSpalte, LSitzX, LSitzY, 25, 'Toilette');
          'K': lokDouble(LSpalte, LSitzX, LSitzY, 25, 'Küche');
          'S': lokDouble(LSpalte, LSitzX, LSitzY, 25, 'Treppe');
          'F': lokFahrer(LSpalte, LSitzX, LSitzY, 25);
          'E': lokEinstieg(LSpalte, LSitzX, LSitzY, 25);
          'J': begin
            lokEinstieg(LSpalte, LSitzX, LSitzY, 25);
            lokDouble(LSpalte, LSitzX, LSitzY, 25, 'WC', true);
          end;
          'O': if (LReihe = 10) and (LSpalte = 2) then
            lokText(LSitzX, LSitzY + SITZ * 0.8, 100, false, 'Oberdeck');
        end;

      end;
    end;
  end; // procedure lokBusSitze

  procedure lokPreisFarben;
  var
    i: integer;
    LColor : TAlphaColor;
  begin
    LPreisListe.CustomSort(PreisListenSort);
    for i := 0 to LPreisListe.Count - 1 do begin
      if StrToCurrDef(LPreisListe[i], 0) = 0 then
        LColor := TAlphaColorRec.Alpha
            or FindParamIntegerReplaced('cl_0', $FFFFFF)
      else
        LColor := TAlphaColorRec.Alpha
            or FindParamIntegerReplaced('cl_' + IntToStr(i + 1), $FFFF00);
      LPreisListe.Objects[i] := TObject(LColor);
    end;
  end; // procedure lokPreisFarben

  procedure lokBusDaten;
  var
    LSql, LPreis, LBafConName, LName: string;
    LData: TDataSet;
    LReihe, LSpalteNum: integer;
    LSpalte: Char;
  begin
    LSql := FInter.GetSqlAndClear(1);
    LBafConName := FindParamStringReplacedLower('db', DC_DEFAULT);
    LName := FInter.Name + '~' + LBafConName;
    SqlAndParams(LBafConName, LName, LSql);
    LData := dataMain.QueryOpen(LBafConName, LName);
    LRowCount := 0;
    while not LData.Eof do begin
      FInter.DebugDbRow(LData);
      LReihe := LData.FieldByName('reihe').AsInteger;
      LSpalte := (LData.FieldByName('spalte').AsString + ' ')[1];
      case LSpalte of
        'A': LSpalteNum := 0;
        'B': LSpalteNum := 1;
        'M': LSpalteNum := 2;
        'C': LSpalteNum := 3;
        'D': LSpalteNum := 4;
      end;
      if (LReihe in [0..17]) and (LSpalteNum in [0..4]) then begin
        LBus[LReihe, LSpalteNum].platz := IntToStr(LReihe) + LSpalte;
        LBus[LReihe, LSpalteNum].status
            := (LData.FieldByName('status').AsString + ' ')[1];
        LBus[LReihe, LSpalteNum].ausrichtung
            := (LData.FieldByName('ausrichtung').AsString + ' ')[1];
        LBus[LReihe, LSpalteNum].preis := LData.FieldByName('preis').AsCurrency;
        LPreis := FormatFloat('0.00', LBus[LReihe, LSpalteNum].preis);
        if LPreisListe.IndexOf(LPreis) = -1 then
          LPreisListe.Add(LPreis);
        LRowCount := System.Math.Max(LRowCount, LReihe + 1);
        LData.Next;
      end;
    end; // while
  end; // procedure lokBusDaten;

begin
  LPreisListe := TStringList.Create;
  try
    LLeft := FindParamSingleReplaced('l', 18) * FZoom;
    LRight := FindParamSingleReplaced('r', 15) * FZoom;
    LFontSize := FindParamIntegerReplaced('fs', 18);
    LFmtString := FindParamStringReplaced('fmt', '0.00');
    LPreisListe.Add('0,00');
    FDrawPaint.Color := TAlphaColorRec.Black;
    FDrawPaint.StrokeWidth := 1;
    FDrawPaint.Style := TSkPaintStyle.Stroke;
    LFillPaint := TSkPaint.Create;
    LFillPaint.Color := TAlphaColorRec.White;
    LFillPaint.Style := TSkPaintStyle.Fill;
    FFontPaint.Color := TAlphaColorRec.Black;
    LEinstiegPaint := TSkPaint.Create;
    LEinstiegPaint.Color := TAlphaColorRec.Silver;
    LEinstiegPaint.Style := TSkPaintStyle.Fill;
    lokBusDaten;
    lokPreisFarben;
    lokBusSitze;
    FY := FY + 615 * LScale;
  finally
    LPreisListe.Free;
  end;
// procedure TBafPdfModule.PdfBus
end;

procedure TBafPdfModule.PdfCheckNewLine;
// Neue Zeile und ggf. neue Seite
var
  LMarginBottom: single;
begin
  if FindParamBooleanReplaced('cnd', true) then begin
    LMarginBottom := FindParamSingleReplaced('mb', 20) * FZoom;
    CheckNewLine(LMarginBottom);
  end;
end;

procedure TBafPdfModule.PdfColfClear;
begin
  FColNum := 0;
  FColMargins[0].Left := 0;
  FColMargins[0].Right := FPageSize.Width;
end;

procedure TBafPdfModule.PdfColfDef;
var
  i: integer;
  LWhiteSpace, LLeft, LRight, LColWidth, LPos: single;
begin
  if FindParamBooleanReplaced('cnd', true) then begin
    FColCount := FindParamIntegerReplaced('cc', 1);
    if FColCount = 1 then
      PdfColfClear
    else begin
      LLeft := FindParamSingleReplaced('l', 18) * FZoom;
      LRight := FindParamSingleReplaced('r', 15) * FZoom;
      LWhiteSpace := FindParamSingleReplaced('ws', 7) * FZoom;
      LColWidth := FPageSize.Width - LLeft - LRight - ((FColCount - 1) * LWhiteSpace);
      LColWidth := LColWidth / FColCount;
      LPos := LLeft;
      for i := 0 to FColCount - 1 do begin
        FColMargins[i].Left := LPos;
        LPos := LPos + LColWidth;
        FColMargins[i].Right := LPos;
        LPos := LPos + LWhiteSpace;
      end;
      FColYPos := FY;
    end;
  end;
end;

{$IFDEF with_zint}
procedure TBafPdfModule.PdfCreateBarcode;
var
  LBitmap: TBitmap;
  LTyp, LFileName: string;
  LSymbol: TZintSymbol;
  LSizeX, LSizeY: integer;
  LTarget: TZintBMPRenderTarget;

  procedure lokCreatePdfPic;
  var
    LRotation: single;
    LImage: ISkImage;
    LStream: TMemoryStream;
    LX, LY, LWidth, LHeight, LMarginBottom: single;
    LRectF: TRectF;
  begin
    LRotation := FindParamSingleReplaced('rot', 0);
    LBitmap.Rotate(LRotation);
    LStream := TMemoryStream.Create;
    try
      LBitmap.SaveToStream(LStream);
      LFileName := FindParamStringReplaced('fn', '');
      if LFileName <> '' then
        LBitmap.SaveToFile(LFileName);
      LStream.Position := 0;
      LImage := TSkImage.MakeFromEncodedStream(LStream);
    finally
      FreeAndNil(LStream);
    end;

    FY := FY + FindParamSingleReplaced('d', 0) * FZoom;
    LMarginBottom := FindParamSingleReplaced('mb', 20) * FZoom;
    LWidth := FindParamSingleReplaced('w', 0) * FZoom;
    LHeight := FindParamSingleReplaced('h', 0) * FZoom;
    LX := FindParamSingleReplaced('x', 0) * FZoom;
    LY := FindParamSingleReplaced('y', FY / FZoom) * FZoom;
    if (LHeight = 0) and (LWidth = 0) then
      LWidth := 100 * FZoom;
    if (LHeight = 0) then begin
      LHeight := LWidth * LImage.Height / System.Math.Max(1, LImage.Width);
    end;
    if (LWidth = 0) then begin
      LWidth := LHeight * LImage.Width / System.Math.Max(1, LImage.Height);
    end;
    LRectF := TRectF.Create(LX, LY, LX + LWidth, LY + LHeight);
    if Assigned(LImage) then
      FCanvas.DrawImageRect(LImage, LRectF);
  end; // procedure lokCreatePdfPic

  procedure lokGetSymbol;
  begin
    LTyp := FindParamStringReplacedLower('typ', 'code_128');
    if LTyp = 'code_128' then
      LSymbol.SymbolType := zsCODE128
    else if LTyp = 'qr' then
      LSymbol.SymbolType := zsQRCODE
    else if LTyp = 'code_11' then
      LSymbol.SymbolType := zsCODE11
    else if LTyp = 'c25_matrix' then
      LSymbol.SymbolType := zsC25MATRIX
    else if LTyp = 'c25_inter' then
      LSymbol.SymbolType := zsC25INTER
    else if LTyp = 'c25_iata' then
      LSymbol.SymbolType := zsC25IATA
    else if LTyp = 'c25_logic' then
      LSymbol.SymbolType := zsC25LOGIC
    else if LTyp = 'c25_ind' then
      LSymbol.SymbolType := zsC25IND
    else if LTyp = 'code_39' then
      LSymbol.SymbolType := zsCODE39
    else if LTyp = 'code_39ex' then
      LSymbol.SymbolType := zsEXCODE39
    else if LTyp = 'eanx' then
      LSymbol.SymbolType := zsEANX
    else if LTyp = 'ean128' then
      LSymbol.SymbolType := zsEAN128
    else if LTyp = 'code_bar' then
      LSymbol.SymbolType := zsCODABAR
    else if LTyp = 'dp_leit' then
      LSymbol.SymbolType := zsDPLEIT
    else if LTyp = 'dp_ident' then
      LSymbol.SymbolType := zsDPIDENT
    else if LTyp = 'code_16k' then
      LSymbol.SymbolType := zsCODE16K
    else if LTyp = 'code_49' then
      LSymbol.SymbolType := zsCODE49
    else if LTyp = 'code_93' then
      LSymbol.SymbolType := zsCODE93
    else if LTyp = 'code_flat' then
      LSymbol.SymbolType := zsFLAT

      ;

    LSymbol.input_mode := UNICODE_MODE;
    LSymbol.primary := StrToArrayOfChar(FindParamStringReplaced('prim', ''));
    LSymbol.Encode(FindParamStringReplaced('z', ''), true);
  end; // procedure lokGetSymbol

begin
  if FindParamBooleanReplaced('cnd', true) then begin
    LSymbol := TZintSymbol.Create(nil);
    try
      lokGetSymbol;

      LBitmap := TBitmap.Create;
      LSizeX := FindParamIntegerReplaced(FExecInter.LineP, 'sx', 800);
      LSizeY := FindParamIntegerReplaced(FExecInter.LineP, 'sy', 800);
      LBitmap.SetSize(LSizeX, LSizeY);
      LBitmap.Clear(TAlphaColorRec.White);
      LTarget := TZintBMPRenderTarget.Create(nil);
      LTarget.Bitmap := LBitmap;
      LTarget.HexagonScale := 1;
      LTarget.RenderAdjustMode := ramScale;
      LTarget.ShowText := false;
      try
        LSymbol.Render(LTarget);
        lokCreatePdfPic;
      finally
        LTarget.Free;
        LBitmap.Free;
      end;
    finally
      LSymbol.Free;
    end;
  end;
// procedure TBafPdfModule.PdfCreateBarcode
end;
{$ENDIF}

procedure TBafPdfModule.PdfDrawDef;
var
  LTyp: string;
begin
  if FindParamBooleanReplaced('cnd', true) then begin
    FDrawPaint.Color := BafColor2AlphaColor(FindParamColor('cl', TColorRec.Black));
    LTyp := FindParamStringReplacedLower('y', 'stroke');

    FDrawPaint.StrokeWidth := FindParamSingleReplaced('w', 1);

    if LTyp = 'stroke' then
      FDrawPaint.Style := TSkPaintStyle.Stroke
    else if LTyp = 'fill' then
      FDrawPaint.Style := TSkPaintStyle.Fill
    else if (LTyp = 'strokeandfill') or (LTyp = 'both') then
      FDrawPaint.Style := TSkPaintStyle.StrokeAndFill
  end;
end;

procedure TBafPdfModule.PdfDrawLine;
var
  LX1, LX2, LY1, LY2: single;
begin
  if FindParamBooleanReplaced('cnd', true) then begin
    FY := FY + FindParamSingleReplaced('d', 0) * FZoom;
    LX1 := FindParamSingleReplaced('x1', 18) * FZoom;
    LX2 := FColMargins[FColNum].Right - FindParamSingleReplaced('x2', 15) * FZoom;
    LY1 := FindParamSingleReplaced('y1', FY / FZoom) * FZoom;
    LY2 := FindParamSingleReplaced('y2', FY / FZoom) * FZoom;
    FCanvas.DrawLine(LX1, LY1, LX2, LY2, FDrawPaint);
  end;
end;

procedure TBafPdfModule.PdfDrawRectangle;
var
  LX, LY, LWidth, LHeight, LRadius: single;
  LRectF: TRectF;
  LTyp: string;
begin
  if FindParamBooleanReplaced('cnd', true) then begin
    LX := FindParamSingleReplaced('x', 0) * FZoom;
    LY := FindParamSingleReplaced('y', 0) * FZoom;
    LWidth := FindParamSingleReplaced('w', 0) * FZoom;
    LHeight := FindParamSingleReplaced('h', 0) * FZoom;
    LRadius := FindParamSingleReplaced('rad', 1) * FZoom;
    LTyp := FindParamStringReplacedLower('j', 'rect');

    LRectF.Left := LX;
    LRectF.Top:= LY;
    LRectF.Width := LWidth;
    LRectF.Height := LHeight;

    if (LTyp = 'rect') or (LTyp = 'rectangle') then
      FCanvas.DrawRect(LRectF, FDrawPaint)
    else if (LTyp = 'round') or (LTyp = 'roundrect') then
      FCanvas.DrawRoundRect(LRectF, LRadius, LRadius, FDrawPaint)
    else if (LTyp = 'circle') or (LTyp = 'oval') then
      FCanvas.DrawOval(LRectF, FDrawPaint);
  end;
end;

procedure TBafPdfModule.PdfExecSub;
// necessary?
var
  LCommand: string;
begin
  if FindParamBooleanReplaced('cnd', true) then begin
    LCommand := FindParamString('cmd', '');
    TBafInterpreterLevel.ExecInNewLevel(LCommand, FExecInter, FInter);
  end;
end;

procedure TBafPdfModule.PdfFont;
var
  LSize, LSkew: single;
begin
  if FindParamBooleanReplaced('cnd', true) then begin
    LSize := FindParamSingleReplaced('s', 10);
    FFont.Size := LSize;
    FLineHeight := LSize * 1.2;
    FFontPaint.Color := BafColor2AlphaColor(FindParamColor('cl', TColorRec.Black));

    LSkew := IfThen(FindParamBooleanReplaced('i', false), -0.15, 0);
    FFont.SkewX := FindParamSingleReplaced('skew', LSkew);
    FFont.Embolden := FindParamBooleanReplaced('b', false);
  end;
end;

procedure TBafPdfModule.PdfGridDef;
var
  i: integer;
begin
  if FindParamBooleanReplaced('cnd', true) then begin
    FY := FY + FindParamSingleReplaced('d', 0) * FZoom;
    FGridColCount := FindParamIntegerReplaced('cc', 2);
    FGridWidth := 0;
    for i := 1 to FGridColCount do begin
      FGridColWidths[i] := FindParamSingleReplaced('cw' + IntToStr(i), 10) * FZoom;
      FGridWidth := FGridWidth + FGridColWidths[i];
    end;
    FGridDefaultRowHeight := FindParamSingleReplaced('h', 10);  // nicht  * FZoom !!!
    FGridLeft := FindParamSingleReplaced('l', 18) * FZoom;
    FGridMarginBottom := FindParamSingleReplaced('mb', 15);
    FGridMarginLeft := FindParamSingleReplaced('ml', 1);
    FGridMarginRight := FindParamSingleReplaced('mr', 1);
    FGridMarginTop := FindParamSingleReplaced('mt', 1);
    FGridDrawLines := FindParamBooleanReplaced('dl', true);
  end;
end;

procedure TBafPdfModule.PdfGridEnd;
begin
  if FindParamBooleanReplaced('cnd', true) then
    PdfGridHorzLine;
end;

procedure TBafPdfModule.PdfGridHorzLine;
begin
  if FGridDrawLines then
    FCanvas.DrawLine(FGridLeft, FY, FGridLeft + FGridWidth, FY, FDrawPaint);
end;

procedure TBafPdfModule.PdfGridRow;
var
  LRowHeight, LLeftPos, LRightPos, LMaxTextWidth, LSize: single;
  LGridMarginLeft, LGridMarginRight, LGridMarginTop, LY: single;
  LPageMarginBottom: single;
  i, j, LColSpan: integer;
  s, t, LAlign: string;
  LText: TStringList;
  LTextAlign: TSkTextAlign;
  LParagraph: ISkParagraph;
  LBuilder: ISkParagraphBuilder;
  LParagraphStyle: ISkParagraphStyle;
  LColor: TAlphaColor;
  LTextStyle: ISkTextStyle;
  LFontWeight: TSkFontWeight;
  LFontWidth: TSkFontWidth;
  LFontSlant: TSkFontSlant;



  procedure lokMakeTextStyle(AFormat: string);
  begin
    LTextStyle := TSkTextStyle.Create;
    if AFormat = '[b]' then
      LFontWeight := TSkFontWeight.Bold
    else if AFormat = '[/b]' then
      LFontWeight := TSkFontWeight.Normal
    else if AFormat = '[b=thin]' then
      LFontWeight := TSkFontWeight.Thin
    else if AFormat = '[b=extralight]' then
      LFontWeight := TSkFontWeight.ExtraLight
    else if AFormat = '[b=light]' then
      LFontWeight := TSkFontWeight.Light
    else if AFormat = '[b=normal]' then
      LFontWeight := TSkFontWeight.Normal
    else if AFormat = '[b=medium]' then
      LFontWeight := TSkFontWeight.Medium
    else if AFormat = '[b=semibold]' then
      LFontWeight := TSkFontWeight.SemiBold
    else if AFormat = '[b=bold]' then
      LFontWeight := TSkFontWeight.Bold
    else if AFormat = '[b=extrabold]' then
      LFontWeight := TSkFontWeight.ExtraBold
    else if AFormat = '[b=black]' then
      LFontWeight := TSkFontWeight.Black
    else if AFormat = '[b=extrablack]' then
      LFontWeight := TSkFontWeight.ExtraBlack
    else if AFormat = '[i]' then
      LFontSlant := TSkFontSlant.Italic
    else if AFormat = '[/i]' then
      LFontSlant := TSkFontSlant.Upright
    else if AFormat = '[i=upright]' then
      LFontSlant := TSkFontSlant.Upright
    else if AFormat = '[i=italic]' then
      LFontSlant := TSkFontSlant.Italic
    else if AFormat = '[i=oblique]' then
      LFontSlant := TSkFontSlant.Oblique
    else if AFormat = '[a=l]' then
      LTextAlign := TSkTextAlign.Left
    else if AFormat = '[a=r]' then
      LTextAlign := TSkTextAlign.Right
    else if AFormat = '[a=c]' then
      LTextAlign := TSkTextAlign.Center
    else if AFormat = '[a=j]' then
      LTextAlign := TSkTextAlign.Justify
    else if copy(AFormat, 1, 3) = '[s=' then
      LSize := StrToFloatDef(copy(AFormat, 4, Length(AFormat) - 4), 10)
    else if copy(AFormat, 1, 4) = '[cl=' then
      LColor := BafColor2AlphaColor(BafName2Color(copy(AFormat, 5, Length(AFormat) - 5)))
    else if AFormat = '[]' then begin
      LFontWeight := TSkFontWeight.Normal;
      LFontWidth := TSkFontWidth.Normal;
      LFontSlant := TSkFontSlant.Upright;
    end;
    LTextStyle.SetFontStyle(TSkFontStyle.Create(LFontWeight, LFontWidth, LFontSlant));
    LTextStyle.Color := LColor;
    LTextStyle.SetFontSize(LSize);
    LBuilder.PushStyle(LTextStyle);
  end; // procedure lokMakeTextStyle

  procedure lokPaint(APara: string);
  var
    LText: string;
    p: integer;
  begin
    LParagraphStyle := TSkParagraphStyle.Create;
    LParagraphStyle.TextAlign := LTextAlign;
    LBuilder := TSkParagraphBuilder.Create(LParagraphStyle);
    lokMakeTextStyle('[]');

    p := Pos('[', APara);
    while p > 0 do begin
      if (p < Length(APara)) and (APara[p + 1] = '[') then
        Delete(APara, p, 1)       // to do a [ in the Text, double it
      else begin
        LText := copy(APara, 1, p - 1);
        Delete(APara, 1, p - 1);
        LBuilder.AddText(LText);
        p := Pos(']', APara);
        if p > 0 then begin
          LText := copy(APara, 1, p);
          Delete(APara, 1, p);
          lokMakeTextStyle(AnsiLowerCase(LText));
        end;
      end;
      p := Pos('[', APara);
    end;

    LBuilder.AddText(APara);
    LParagraph := LBuilder.Build;
    LParagraph.Layout(LMaxTextWidth);
//    if (FY + LParagraph.Height + LMarginBottomParagraph) > FPageSize.Height then
//      PdfAddCol;
    LParagraph.Paint(FCanvas, LLeftPos + LGridMarginLeft, FY + LY);
    LY := LY + LParagraph.Height; // + LDist;
  end; // procedure lokPaint

begin
  if FindParamBooleanReplaced('cnd', true) then begin
    LText := TStringList.Create;
    try
      LRowHeight := FindParamSingleReplaced('h', FGridDefaultRowHeight) * FZoom;
      PdfGridHorzLine;
      PdfGridVertLine(FGridLeft, LRowHeight);
      LLeftPos := FGridLeft;
      i := 1;
      while i <= FGridColCount do begin
        LRightPos := LLeftPos + FGridColWidths[i];
        s := IntToStr(i);
        LColSpan := FindParamIntegerReplaced('cs' + s, 1);
        for j := 2 to LColSpan do
          LRightPos := LRightPos + FGridColWidths[i + j - 1];
        t := FindParamStringReplaced('cn' + s, '');
        if t = '' then begin
          t := FindParamStringReplaced('c' + s, '');
          t := FExecInter.ReplaceFunctions(t);
        end;
        LText.Text := t;
        LAlign := AnsiLowerCase(FindParamStringLower('a' + s, ''));
        if LAlign = 'l' then
          LTextAlign := TSkTextAlign.Left
        else if LAlign = 'c' then
          LTextAlign := TSkTextAlign.Center
        else if LAlign = 'r' then
          LTextAlign := TSkTextAlign.Right
        else if LAlign = 'j' then
          LTextAlign := TSkTextAlign.Justify;
        LColor := BafColor2AlphaColor(FindParamColor('cl' + s, TColorRec.Black));
        LSize := FindParamSingleReplaced('s' + s, 10);
        LGridMarginLeft := FindParamSingleReplaced('ml' + s, FGridMarginLeft) * FZoom;
        LGridMarginRight := FindParamSingleReplaced('mr' + s, FGridMarginRight) * FZoom;
        LGridMarginTop := FindParamSingleReplaced('mt' + s, FGridMarginTop) * FZoom;
        LMaxTextWidth := LRightPos - LLeftPos - LGridMarginLeft - LGridMarginRight;
        LY := LGridMarginTop;
        for j := 0 to LText.Count - 1 do
          lokPaint(LText[j]);
        PdfGridVertLine(LRightPos, LRowHeight);
        LLeftPos := LRightPos;
        inc(i, LColSpan);
      end;
    finally
      LText.Free;
    end;
    FY := FY + LRowHeight;
    LPageMarginBottom := FindParamSingleReplaced('mb', 15) * FZoom;
    if FY > (FPageSize.Height - LPageMarginBottom) then
      PdfAddCol;
  end;
// procedure TBafPdfModule.PdfGridRow
end;

procedure TBafPdfModule.PdfGridVertLine(AXPos, AHeight: single);
begin
  if FGridDrawLines then
    FCanvas.DrawLine(AXPos, FY, AXPos, FY + AHeight, FDrawPaint);
end;

procedure TBafPdfModule.PdfInsertPic;
var
  LName: string;
  LX, LY, LWidth, LHeight, LMarginBottom: single;
  LImage: ISkImage;
  LRectF: TRectF;
  LFileName: string;
begin
  if FindParamBooleanReplaced('cnd', true) then begin
    LFileName := FindParamStringReplaced('fn', '');
    LImage := TSkImage.MakeFromEncodedFile(LFileName);
    FY := FY + FindParamSingleReplaced('d', 0) * FZoom;
    LMarginBottom := FindParamSingleReplaced('mb', 20) * FZoom;
    LWidth := FindParamSingleReplaced('w', 0) * FZoom;
    LHeight := FindParamSingleReplaced('h', 0) * FZoom;
    LX := FindParamSingleReplaced('x', 0) * FZoom;
    LY := FindParamSingleReplaced('y', -1) * FZoom;
    if (LHeight = 0) and (LWidth = 0) then
      LWidth := 100 * FZoom;
    if (LHeight = 0) then begin
      LHeight := LWidth * LImage.Height / System.Math.Max(1, LImage.Width);
    end;
    if (LWidth = 0) then begin
      LWidth := LHeight * LImage.Width / System.Math.Max(1, LImage.Height);
    end;
    if LY < 0 then begin
      FY := FY - LHeight;
      if FY < LMarginBottom then begin
        PdfAddPage;
        FY := FY - LHeight;
      end;
      LY := FY;
    end;
    LRectF := TRectF.Create(LX, LY, LX + LWidth, LY + LHeight);
    FCanvas.DrawImageRect(LImage, LRectF);
  end;
end;

procedure TBafPdfModule.PdfLine(ALineFeed: boolean);
var
  LText, LGroup, s: string;
  LWidth, LLeft, LRight, LEinr: single;
  LAlign: TBafAlignment;
  LFirst: boolean;

  function lokGroupChange: boolean;
//  var
//    LStyles: TPdfFontStyles;
//    LSize: single;
  begin
//    LFirst := FLineGroup.Count = 0;
//    s := FLineGroup.Values[LGroup];
//    result := s <> LText;
//    FLineGroup.Values[LGroup] := LText;
//    if result and not LFirst then begin
//      FY := FY - FindParamSingleReplaced('dy', 0) * FZoom;
//      CheckNewLine(FindParamSingleReplaced('mb', 20) * FZoom);
//      LSize := FindParamSingleReplaced('s', 10);
//      FLineHeight := LSize * 1.2;
//      LStyles := [];
//      if FindParamBooleanReplaced('b', false) then
//        Include(LStyles, pfsBold);
//      if FindParamBooleanReplaced('i', false) then
//        Include(LStyles, pfsItalic);
//      FPDF.Canvas.SetFont(FindParamString('n', 'Helvetica'), LSize, LStyles);
//      FPDF.Canvas.SetRGBFillColor(FindParamColor('cl', TColorRec.Black));
//    end;
  end; // function lokGroupChange

begin
  if FindParamBooleanReplaced('cnd', true) then begin
    LText := FindParamStringReplaced('cn', '');
    if LText = '' then begin
      LText := FindParamStringReplaced('c', '');
      LText := FExecInter.ReplaceFunctions(LText);
    end;
    LGroup := FindParamStringReplaced('grp', '');
    if (LGroup = '') or lokGroupChange then begin
      LAlign := FInter.FindParamAlignment(FExecInter.LineP, 'a', taLeftJustify);
      LLeft := FindParamSingleReplaced('l', 18) * FZoom;
      LRight := FindParamSingleReplaced('r', 15) * FZoom;
      LEinr := CalcTextLeft(LText, FColMargins[FColNum].Right - FColMargins[FColNum].Left
          - LRight - LLeft, LAlign);

      FCanvas.DrawSimpleText(LText, LLeft + LEinr, FY, FFont, FFontPaint);
      if ALineFeed then begin
        FY := FY + FindParamSingleReplaced('d', 0) * FZoom;
        CheckNewLine(FindParamSingleReplaced('mb', 15) * FZoom);
      end;
    end;
  end;
end;



procedure TBafPdfModule.PdfMaxSizeText;
var
  s, LAlign: string;
  LWidth, LLeft, LRight, LSize, LMarginBottom, LMarginBottomParagraph,
      LMaxTextWidth, LMaxTextHeight, LHeight, LDist: single;
  LTextAlign: TSkTextAlign;
  LColor: TAlphaColor;
  i: integer;
  LParagraph: ISkParagraph;
  LBuilder: ISkParagraphBuilder;
  LParagraphStyle: ISkParagraphStyle;
  LTextStyle: ISkTextStyle;
  LFontWeight: TSkFontWeight;
  LFontWidth: TSkFontWidth;
  LFontSlant: TSkFontSlant;

  procedure lokMakeTextStyle(AFormat: string);
  begin
    LTextStyle := TSkTextStyle.Create;
    if AFormat = '[b]' then
      LFontWeight := TSkFontWeight.Bold
    else if AFormat = '[/b]' then
      LFontWeight := TSkFontWeight.Normal
    else if AFormat = '[b=thin]' then
      LFontWeight := TSkFontWeight.Thin
    else if AFormat = '[b=extralight]' then
      LFontWeight := TSkFontWeight.ExtraLight
    else if AFormat = '[b=light]' then
      LFontWeight := TSkFontWeight.Light
    else if AFormat = '[b=normal]' then
      LFontWeight := TSkFontWeight.Normal
    else if AFormat = '[b=medium]' then
      LFontWeight := TSkFontWeight.Medium
    else if AFormat = '[b=semibold]' then
      LFontWeight := TSkFontWeight.SemiBold
    else if AFormat = '[b=bold]' then
      LFontWeight := TSkFontWeight.Bold
    else if AFormat = '[b=extrabold]' then
      LFontWeight := TSkFontWeight.ExtraBold
    else if AFormat = '[b=black]' then
      LFontWeight := TSkFontWeight.Black
    else if AFormat = '[b=extrablack]' then
      LFontWeight := TSkFontWeight.ExtraBlack
    else if AFormat = '[i]' then
      LFontSlant := TSkFontSlant.Italic
    else if AFormat = '[/i]' then
      LFontSlant := TSkFontSlant.Upright
    else if AFormat = '[i=upright]' then
      LFontSlant := TSkFontSlant.Upright
    else if AFormat = '[i=italic]' then
      LFontSlant := TSkFontSlant.Italic
    else if AFormat = '[i=oblique]' then
      LFontSlant := TSkFontSlant.Oblique
    else if AFormat = '[a=l]' then
      LTextAlign := TSkTextAlign.Left
    else if AFormat = '[a=r]' then
      LTextAlign := TSkTextAlign.Right
    else if AFormat = '[a=c]' then
      LTextAlign := TSkTextAlign.Center
    else if AFormat = '[a=j]' then
      LTextAlign := TSkTextAlign.Justify
    else if copy(AFormat, 1, 4) = '[cl=' then
      LColor := BafColor2AlphaColor(BafName2Color(copy(AFormat, 5, Length(AFormat) - 5)))
    else if AFormat = '[]' then begin
      LFontWeight := TSkFontWeight.Normal;
      LFontWidth := TSkFontWidth.Normal;
      LFontSlant := TSkFontSlant.Upright;
    end;
    LTextStyle.SetFontStyle(TSkFontStyle.Create(LFontWeight, LFontWidth, LFontSlant));
    LTextStyle.Color := LColor;
    LTextStyle.SetFontSize(LSize);
    LBuilder.PushStyle(LTextStyle);
  end; // procedure lokMakeTextStyle


  procedure lokPaint(APara: string);
  var
    LText: string;
    p: integer;
  begin
    LParagraphStyle := TSkParagraphStyle.Create;
    LParagraphStyle.TextAlign := LTextAlign;
    LBuilder := TSkParagraphBuilder.Create(LParagraphStyle);
    lokMakeTextStyle('[]');

    p := Pos('[', APara);
    while p > 0 do begin
      if (p < Length(APara)) and (APara[p + 1] = '[') then
        Delete(APara, p, 1)       // to do a [ in the Text, double it
      else begin
        LText := copy(APara, 1, p - 1);
        Delete(APara, 1, p - 1);
        LBuilder.AddText(LText);
        p := Pos(']', APara);
        if p > 0 then begin
          LText := copy(APara, 1, p);
          Delete(APara, 1, p);
          lokMakeTextStyle(AnsiLowerCase(LText));
        end;
      end;
      p := Pos('[', APara);
    end;

    LBuilder.AddText(APara);
    LParagraph := LBuilder.Build;
    LParagraph.Layout(LMaxTextWidth);
  end; // procedure lokPaint

begin
  if FindParamBooleanReplaced('cnd', true) then begin
    LAlign := AnsiLowerCase(FindParamStringLower('a', ''));
    if LAlign = 'l' then
      LTextAlign := TSkTextAlign.Left
    else if LAlign = 'c' then
      LTextAlign := TSkTextAlign.Center
    else if LAlign = 'r' then
      LTextAlign := TSkTextAlign.Right
    else if LAlign = 'j' then
      LTextAlign := TSkTextAlign.Justify;
    LLeft := FindParamSingleReplaced('l', 18) * FZoom;
    LRight := FindParamSingleReplaced('r', 15) * FZoom;
    LMarginBottom := FindParamSingleReplaced('mb', 20) * FZoom;
    LMarginBottomParagraph := FindParamSingleReplaced('mbp', 20) * FZoom;
    LMaxTextWidth := (FColMargins[FColNum].Right - FColMargins[FColNum].Left - LRight - LLeft);
    LSize := FindParamSingleReplaced('s', 10);
    LColor := BafColor2AlphaColor(FindParamColor('cl', TColorRec.Black));
    LDist := FindParamSingleReplaced('d', LSize / 2);
    LMaxTextHeight := FindParamSingleReplaced('h', 10) * FZoom;

    s := FindParamStringReplaced('cn', '');
    if s = '' then begin
      s := FindParamStringReplaced('c', '');
      s := FExecInter.ReplaceFunctions(s);
    end;

    lokPaint(s);
    while LParagraph.Height > LMaxTextHeight do begin
      LSize := LSize * 0.95;
      lokPaint(s);
    end;
    if (FY + LParagraph.Height + LMarginBottomParagraph) > FPageSize.Height then
      PdfAddCol;
    LParagraph.Paint(FCanvas, FColMargins[FColNum].Left + LLeft, FY);
    FY := FY + LParagraph.Height + LDist;
  end;
// procedure TBafPdfModule.PdfMaxSizeText
end;

procedure TBafPdfModule.PdfMultiline;
var
  s, LAlign: string;
  LWidth, LLeft, LRight,LSize, LMarginBottom, LMarginBottomParagraph,
      LMaxTextWidth, LHeight, LDist: single;
  LColor: TAlphaColor;
  LText: TStringList;
  i: integer;
  LTextAlign: TSkTextAlign;

  procedure lokPaint(APara: string);
  var
    LParagraph: ISkParagraph;
    LBuilder: ISkParagraphBuilder;
    LTextStyle: ISkTextStyle;
    LParagraphStyle: ISkParagraphStyle;
    LHeight: single;

    procedure lokSplit(APara: string);
    var
      LText, LRest, LText2: string;
      i, p, LPos: integer;
      LMaxHeight: single;
    begin
      LMaxHeight := FPageSize.Height - FY - LMarginBottom;
      LPos := round(Length(APara) * 1.1 * LMaxHeight / LParagraph.Height);
      for i := LPos downto 1 do begin
        if APara[i] = ' ' then begin
          LBuilder := nil;
          LBuilder := TSkParagraphBuilder.Create(LParagraphStyle);
          LBuilder.PushStyle(LTextStyle);
          LBuilder.AddText(copy(APara, 1, i - 1));
          LParagraph := LBuilder.Build;
          LParagraph.Layout(LMaxTextWidth);
          if LParagraph.Height <= LMaxHeight then begin
            LParagraph.Paint(FCanvas, FColMargins[FColNum].Left + LLeft, FY);
            PdfAddCol;
            Delete(APara, 1, i);
            LMaxHeight := FPageSize.Height - FY - LMarginBottom;

            LBuilder := nil;
            LBuilder := TSkParagraphBuilder.Create(LParagraphStyle);
            LBuilder.PushStyle(LTextStyle);
            LBuilder.AddText(APara);
            LParagraph := LBuilder.Build;
            LParagraph.Layout(LMaxTextWidth);
            if LParagraph.Height <= LMaxHeight then begin
              LParagraph.Paint(FCanvas, FColMargins[FColNum].Left + LLeft, FY);
              FY := FY + LParagraph.Height + LDist;
            end
            else
              lokSplit(APara);
            exit;
          end;
        end;
      end;
      raise Exception.Create('unable to split');
    end; // procedure lokSplit

  begin
    LParagraphStyle := TSkParagraphStyle.Create;
    LParagraphStyle.TextAlign := LTextAlign;
    LBuilder := TSkParagraphBuilder.Create(LParagraphStyle);

    LTextStyle := TSkTextStyle.Create;
    LTextStyle.Color := LColor;
    LTextStyle.SetFontSize(LSize);
    LTextStyle.SetFontStyle(TSkFontStyle.Create(TSkFontWeight.Normal, TSkFontWidth.Normal, TSkFontSlant.Upright));
    LBuilder.PushStyle(LTextStyle);
    LBuilder.AddText(APara);
    LParagraph := LBuilder.Build;
    LParagraph.Layout(LMaxTextWidth);
    if (FY + LParagraph.Height + LMarginBottom) > FPageSize.Height then
      lokSplit(APara + ' ')
    else begin
      LParagraph.Paint(FCanvas, FColMargins[FColNum].Left + LLeft, FY);
      FY := FY + LParagraph.Height + LDist;
    end;
    if (FY + LMarginBottomParagraph) > FPageSize.Height then
      PdfAddCol;
  end; // procedure lokPaint

begin
  if FindParamBooleanReplaced('cnd', true) then begin
    LAlign := AnsiLowerCase(FindParamStringLower('a', ''));
    if LAlign = 'l' then
      LTextAlign := TSkTextAlign.Left
    else if LAlign = 'c' then
      LTextAlign := TSkTextAlign.Center
    else if LAlign = 'r' then
      LTextAlign := TSkTextAlign.Right
    else if LAlign = 'j' then
      LTextAlign := TSkTextAlign.Justify;
    LLeft := FindParamSingleReplaced('l', 18) * FZoom;
    LRight := FindParamSingleReplaced('r', 15) * FZoom;
    LMarginBottom := FindParamSingleReplaced('mb', 20) * FZoom;
    LMarginBottomParagraph := FindParamSingleReplaced('mbp', 20) * FZoom;
    LMaxTextWidth := (FColMargins[FColNum].Right - FColMargins[FColNum].Left - LRight - LLeft);
    LSize := FindParamSingleReplaced('s', 10);
    LDist := FindParamSingleReplaced('d', LSize / 2);
    LColor := BafColor2AlphaColor(FindParamColor('cl', TColorRec.Black));

    LText := TStringList.Create;
    try
      s := FindParamStringReplaced('cn', '');
      if s = '' then begin
        s := FindParamStringReplaced('c', '');
        s := FExecInter.ReplaceFunctions(s);
      end;
      LText.Text := s;
      for i := 0 to LText.Count - 1 do
        lokPaint(LText[i]);
    finally
      LText.Free;
    end;
  end;
// procedure TBafPdfModule.PdfMultiline
end;

procedure TBafPdfModule.PdfMultilineBB2;
var
  s, LAlign: string;
  LWidth, LLeft, LRight, LSize, LMarginBottom, LMarginBottomParagraph,
      LMaxTextWidth, LHeight, LDist, LDistLine: single;
  LTextAlign: TSkTextAlign;
  LColor: TAlphaColor;
  LText: TStringList;
  i: integer;
  LParagraph: ISkParagraph;
  LBuilder: ISkParagraphBuilder;
  LParagraphStyle: ISkParagraphStyle;
  LTextStyle: ISkTextStyle;
  LFontWeight: TSkFontWeight;
  LFontWidth: TSkFontWidth;
  LFontSlant: TSkFontSlant;

  procedure lokMakeTextStyle(AFormat: string);
  begin
    LTextStyle := TSkTextStyle.Create;
    if AFormat = '[b]' then
      LFontWeight := TSkFontWeight.Bold
    else if AFormat = '[/b]' then
      LFontWeight := TSkFontWeight.Normal
    else if AFormat = '[b=thin]' then
      LFontWeight := TSkFontWeight.Thin
    else if AFormat = '[b=extralight]' then
      LFontWeight := TSkFontWeight.ExtraLight
    else if AFormat = '[b=light]' then
      LFontWeight := TSkFontWeight.Light
    else if AFormat = '[b=normal]' then
      LFontWeight := TSkFontWeight.Normal
    else if AFormat = '[b=medium]' then
      LFontWeight := TSkFontWeight.Medium
    else if AFormat = '[b=semibold]' then
      LFontWeight := TSkFontWeight.SemiBold
    else if AFormat = '[b=bold]' then
      LFontWeight := TSkFontWeight.Bold
    else if AFormat = '[b=extrabold]' then
      LFontWeight := TSkFontWeight.ExtraBold
    else if AFormat = '[b=black]' then
      LFontWeight := TSkFontWeight.Black
    else if AFormat = '[b=extrablack]' then
      LFontWeight := TSkFontWeight.ExtraBlack
    else if AFormat = '[i]' then
      LFontSlant := TSkFontSlant.Italic
    else if AFormat = '[/i]' then
      LFontSlant := TSkFontSlant.Upright
    else if AFormat = '[i=upright]' then
      LFontSlant := TSkFontSlant.Upright
    else if AFormat = '[i=italic]' then
      LFontSlant := TSkFontSlant.Italic
    else if AFormat = '[i=oblique]' then
      LFontSlant := TSkFontSlant.Oblique
    else if AFormat = '[a=l]' then
      LTextAlign := TSkTextAlign.Left
    else if AFormat = '[a=r]' then
      LTextAlign := TSkTextAlign.Right
    else if AFormat = '[a=c]' then
      LTextAlign := TSkTextAlign.Center
    else if AFormat = '[a=j]' then
      LTextAlign := TSkTextAlign.Justify
    else if copy(AFormat, 1, 3) = '[s=' then
      LSize := StrToFloatDef(copy(AFormat, 4, Length(AFormat) - 4), 10)
    else if copy(AFormat, 1, 3) = '[d=' then
      LDistLine := StrToFloatDef(copy(AFormat, 4, Length(AFormat) - 4), LDist)
    else if copy(AFormat, 1, 4) = '[cl=' then
      LColor := BafColor2AlphaColor(BafName2Color(copy(AFormat, 5, Length(AFormat) - 5)))
    else if AFormat = '[]' then begin
      LFontWeight := TSkFontWeight.Normal;
      LFontWidth := TSkFontWidth.Normal;
      LFontSlant := TSkFontSlant.Upright;
    end;
    LTextStyle.SetFontStyle(TSkFontStyle.Create(LFontWeight, LFontWidth, LFontSlant));
    LTextStyle.Color := LColor;
    LTextStyle.SetFontSize(LSize);
    LBuilder.PushStyle(LTextStyle);
  end; // procedure lokMakeTextStyle


  procedure lokPaint(APara: string);
  var
    LText: string;
    p: integer;
  begin
    LDistLine := LDist;
    LParagraphStyle := TSkParagraphStyle.Create;
    LParagraphStyle.TextAlign := LTextAlign;
    LBuilder := TSkParagraphBuilder.Create(LParagraphStyle);
    lokMakeTextStyle('[]');

    p := Pos('[', APara);
    while p > 0 do begin
      if (p < Length(APara)) and (APara[p + 1] = '[') then
        Delete(APara, p, 1)       // to do a [ in the Text, double it
      else begin
        LText := copy(APara, 1, p - 1);
        Delete(APara, 1, p - 1);
        LBuilder.AddText(LText);
        p := Pos(']', APara);
        if p > 0 then begin
          LText := copy(APara, 1, p);
          Delete(APara, 1, p);
          lokMakeTextStyle(AnsiLowerCase(LText));
        end;
      end;
      p := Pos('[', APara);
    end;

    LBuilder.AddText(APara);
    LParagraph := LBuilder.Build;
    LParagraph.Layout(LMaxTextWidth);
    if (FY + LParagraph.Height + LMarginBottomParagraph) > FPageSize.Height then
      PdfAddCol;
    LParagraph.Paint(FCanvas, FColMargins[FColNum].Left + LLeft, FY);
    FY := FY + LParagraph.Height + LDistLine;
  end; // procedure lokPaint

begin
  if FindParamBooleanReplaced('cnd', true) then begin
    LAlign := AnsiLowerCase(FindParamStringLower('a', ''));
    if LAlign = 'l' then
      LTextAlign := TSkTextAlign.Left
    else if LAlign = 'c' then
      LTextAlign := TSkTextAlign.Center
    else if LAlign = 'r' then
      LTextAlign := TSkTextAlign.Right
    else if LAlign = 'j' then
      LTextAlign := TSkTextAlign.Justify;
    LLeft := FindParamSingleReplaced('l', 18) * FZoom;
    LRight := FindParamSingleReplaced('r', 15) * FZoom;
    LMarginBottom := FindParamSingleReplaced('mb', 20) * FZoom;
    LMarginBottomParagraph := FindParamSingleReplaced('mbp', 20) * FZoom;
    LMaxTextWidth := (FColMargins[FColNum].Right - FColMargins[FColNum].Left - LRight - LLeft);
    LSize := FindParamSingleReplaced('s', 10);
    LColor := BafColor2AlphaColor(FindParamColor('cl', TColorRec.Black));
    LDist := FindParamSingleReplaced('d', LSize / 2);



    LText := TStringList.Create;
    try
      s := FindParamStringReplaced('cn', '');
      if s = '' then begin
        s := FindParamStringReplaced('c', '');
        s := FExecInter.ReplaceFunctions(s);
      end;
      LText.Text := s;
      for i := 0 to LText.Count - 1 do
        lokPaint(LText[i]);
    finally
      LText.Free;
    end;
  end;
// procedure TBafPdfModule.PdfMultilineBB2
end;

procedure TBafPdfModule.PdfSetY;
var
  s: string;
begin
  if FindParamBooleanReplaced('cnd', true) then begin
    if FindParam('y', s) then
      FY := FindParamSingleReplaced('y', 0) * FZoom;
    FY := FY + FindParamSingleReplaced('d', 0) * FZoom;
  end;
end;

procedure TBafPdfModule.PdfStart(AIntern: boolean = false; ALandscape: boolean = false; AFileName: string = '');
var
  LDialog: TSaveDialog;

  procedure lokStartDoc;
  begin
    FDocumentFileName := AFileName;
    FTemporaryFileName := FindParamStringReplaced('tfn', FDocumentFileName);
    FDocumentStream := TFileStream.Create(FTemporaryFileName, fmCreate);
    FDocument := TSkDocument.MakePDF(FDocumentStream);
    if not AIntern then
      FLandscape := FindParamBooleanReplaced('pal', false)
    else
      FLandscape := ALandscape;
    FPage := 0;
    PdfAddPage;
    PdfColfClear;

    FFont := TSkFont.Create;
    FFont.Size := 10;
    FLineHeight := 12;
    FFontPaint := TSkPaint.Create;
    FFontPaint.Color := TAlphaColorRec.Black;
    FDrawPaint := TSkPaint.Create;
    FDrawPaint.Color := TAlphaColorRec.Black;
    FDrawPaint.Style := TSkPaintStyle.Stroke;
  end; // procedure lokStartDoc

begin
  if FindParamBooleanReplaced('cnd', true) then begin
    FLineGroup.Clear;
    FDocumentFileName := '';

    if AFileName = '' then
      AFileName := FindParamStringReplaced('fn', '');
    if AFileName = '' then begin
      LDialog := TSaveDialog.Create(nil);
      try
        LDialog.Filter := TBafTranslationModule.BafTranslate('$T(FILTER_PDF)');
        if LDialog.Execute then begin
          AFileName := LDialog.FileName;
          if FileExists(AFileName) then begin
            ShowMessage(Format(TBafTranslationModule.BafTranslate('$T(FILE_EXISTS)'), [AFileName]));
          end
          else
            lokStartDoc;
        end;
      finally
        LDialog.Free;
      end;
    end
    else
      lokStartDoc;
  end;
end;

procedure TBafPdfModule.PdfStop(ADoOpen: boolean);
var
  LSleep: integer;
begin
  if FindParamBooleanReplaced('cnd', true) then begin
    LSleep := FindParamIntegerReplaced('sleep', 1);
    if Assigned(FCanvas) then begin
      FDocument.EndPage;
      FCanvas := nil;
    end;
    if FDocument = nil then
      exit;
    FDocument.Close;
    FreeAndNil(FDocumentStream);
    FDocument := nil;
    FFont := nil;
    FFontPaint := nil;
    if FileExists(FTemporaryFileName) and (FDocumentFileName <> '')
        and (FDocumentFileName <> FTemporaryFileName) then begin
      Application.ProcessMessages;
      Sleep(LSleep);
      Application.ProcessMessages;
      DeleteFile(FDocumentFileName);
      Application.ProcessMessages;
      Sleep(LSleep);
      Application.ProcessMessages;
      RenameFile(FTemporaryFileName, FDocumentFileName);
    end;
    if (FDocumentFileName <> '')
        and (ADoOpen or FindParamBooleanReplaced('o', false)) then
      BafOpenFile(FDocumentFileName);
  end;
end;

procedure TBafPdfModule.PdfVBus;
const
  SITZ = 8;
  ZWI = 1.9;
  ICONS = 'T:\Tools Gruppenrechte\BafClient2\icons\';


type
  TBusPlatz = record
    platz: string[3];
    status: Char;
    ausrichtung: Char;
    preis: currency;
  end;

var
  LBus: array[0..17, 0..4] of TBusPlatz;
  LRowCount: integer;
  LPlatz: TBusPlatz;
  LPreisListe: TStringList;
  LFontSize: integer;
  LFmtString: string;
  LScale, LSitz, L80: single;
  LFillPaint, LFillPaintGray: ISkPaint;
  LEinstiegPaint: ISkPaint;

  LLeft, LTop, LBottom, LDrawHeight: single;


  procedure lokText(x1, y1, ASize: single; ABold: boolean; AText: string);
  begin
    FFont.Size := ASize;
    FFont.Embolden := ABold;
    FCanvas.DrawSimpleText(AText, x1, y1, FFont, FFontPaint);
  end; // procedure lokText

  procedure lokTextZentriert(ASitzX, ASitzY, AWidth, ASize: single;
      AText: string; AColor: TAlphaColor = TAlphaColorRec.Black);
  var
    LParagraphStyle: ISkParagraphStyle;
    LParagraph: ISkParagraph;
    LBuilder: ISkParagraphBuilder;
    LTextStyle: ISkTextStyle;
  begin
    LParagraphStyle := TSkParagraphStyle.Create;
    LParagraphStyle.TextAlign := TSkTextAlign.Center;
    LBuilder := TSkParagraphBuilder.Create(LParagraphStyle);

    LTextStyle := TSkTextStyle.Create;
    LTextStyle.SetFontStyle(TSkFontStyle.Create(TSkFontWeight.Bold, TSkFontWidth.Normal, TSkFontSlant.Upright));
    LTextStyle.Color := AColor;
    LTextStyle.SetFontSize(ASize);
    LBuilder.PushStyle(LTextStyle);

    LBuilder.AddText(AText);
    LParagraph := LBuilder.Build;
    LParagraph.Layout(AWidth);
    LParagraph.Paint(FCanvas, ASitzX, ASitzY);
  end; // procedure lokTextZentriert

  procedure lokBusSitz(AReihe, ASpalte: integer; ASitzX, ASitzY: single;
      AZeile2: string; ASize: integer; ABold: boolean; AFileName: string = '');
  var
    LRectF: TRectF;
    LImage: ISkImage;
  begin
    case LPlatz.ausrichtung of
      'H': begin
        FCanvas.DrawRect(TRectF.Create(ASitzX, ASitzY, ASitzX + LSitz, ASitzY + LSitz), LFillPaint);
        FCanvas.DrawRect(TRectF.Create(ASitzX, ASitzY, ASitzX + LSitz, ASitzY + LSitz * 0.15), LFillPaintGray);
        FCanvas.DrawRect(TRectF.Create(ASitzX, ASitzY, ASitzX + LSitz, ASitzY + LSitz), FDrawPaint);
        FCanvas.DrawLine(ASitzX, ASitzY + LSitz * 0.15, ASitzX + LSitz, ASitzY + LSitz * 0.15, FDrawPaint);
        lokText(ASitzX + LSitz * 0.15, ASitzY + LSitz * 0.45, ASize, ABold, AZeile2);
      end;
      'R': begin
        FCanvas.DrawRect(TRectF.Create(ASitzX, ASitzY, ASitzX + LSitz, ASitzY + LSitz), LFillPaint);
        FCanvas.DrawRect(TRectF.Create(ASitzX, ASitzY, ASitzX + LSitz * 0.15, ASitzY + LSitz), LFillPaintGray);
        FCanvas.DrawRect(TRectF.Create(ASitzX, ASitzY, ASitzX + LSitz, ASitzY + LSitz), FDrawPaint);
        FCanvas.DrawLine(ASitzX + LSitz * 0.15, ASitzY, ASitzX + LSitz * 0.15, ASitzY + LSitz, FDrawPaint);
        lokText(ASitzX + LSitz * 0.22, ASitzY + LSitz * 0.57, ASize, ABold, AZeile2);
      end;
      'L': begin
        FCanvas.DrawRect(TRectF.Create(ASitzX, ASitzY, ASitzX + LSitz, ASitzY + LSitz), LFillPaint);
        FCanvas.DrawRect(TRectF.Create(ASitzX + LSitz * 0.85, ASitzY, ASitzX + LSitz, ASitzY + LSitz), LFillPaintGray);
        FCanvas.DrawRect(TRectF.Create(ASitzX, ASitzY, ASitzX + LSitz, ASitzY + LSitz), FDrawPaint);
        FCanvas.DrawLine(ASitzX + LSitz * 0.85, ASitzY, ASitzX + LSitz * 0.85, ASitzY + LSitz, FDrawPaint);
        lokText(ASitzX + LSitz * 0.05, ASitzY + LSitz * 0.57, ASize, ABold, AZeile2);
      end;
      else begin
        FCanvas.DrawRect(TRectF.Create(ASitzX, ASitzY, ASitzX + LSitz, ASitzY + LSitz), LFillPaint);
        FCanvas.DrawRect(TRectF.Create(ASitzX, ASitzY + L80, ASitzX + LSitz, ASitzY + LSitz), LFillPaintGray);
        if AFileName <> '' then begin
          LImage := TSkImage.MakeFromEncodedFile(ICONS + AFileName);
          FCanvas.DrawImageRect(LImage, TRectF.Create(ASitzX + 0.2 * LSitz, ASitzY + 0.15 * LSitz,
              ASitzX + 0.8 * LSitz, ASitzY + 0.75 * LSitz));
        end;
        FCanvas.DrawRect(TRectF.Create(ASitzX, ASitzY, ASitzX + LSitz, ASitzY + LSitz), FDrawPaint);
        FCanvas.DrawLine(ASitzX, ASitzY + L80, ASitzX + LSitz, ASitzY + L80, FDrawPaint);
        if AFileName = '' then
          lokText(ASitzX + LSitz * 0.15, ASitzY + LSitz * 0.7, ASize, ABold, AZeile2);
      end;
    end;
  end; // procedure lokBusSitz

  procedure lokIcon(ASitzX, ASitzY: single; AFileName: string; ABreitrahmen: boolean = false);
  var
    LImage: ISkImage;
    LRectF: TRectF;
    LMitte: single;
  begin
    if ABreitrahmen then begin
      LImage := TSkImage.MakeFromEncodedFile(ICONS + AFileName);
      LMitte := (LSitz + ZWI * FZoom) / 2;
      LRectF := TRectF.Create(ASitzX + LMitte, ASitzY,
          ASitzX + LMitte + LSitz, ASitzY + LSitz);
      LRectF.Inflate(-LSitz * 0.1, -LSitz * 0.1);
      FCanvas.DrawImageRect(LImage, LRectF);
      FCanvas.DrawRect(TRectF.Create(ASitzX, ASitzY,
          ASitzX + 2 * LSitz + ZWI * FZoom, ASitzY + LSitz), FDrawPaint);
    end
    else begin
      LImage := TSkImage.MakeFromEncodedFile(ICONS + AFileName);
      LRectF := TRectF.Create(ASitzX, ASitzY, ASitzX + LSitz, ASitzY + LSitz);
      FCanvas.DrawImageRect(LImage, LRectF);
    end;
  end; // procedure lokIcon

  procedure lokEinstieg(ASpalte: integer; ASitzX, ASitzY: single; AKombi: boolean);
  var
    LImage: ISkImage;
    LRectF: TRectF;
  begin
    if AKombi then begin
      LImage := TSkImage.MakeFromEncodedFile(ICONS + 'Icon_kombi.png');
      LRectF := TRectF.Create(ASitzX, ASitzY, ASitzX + 2 * LSitz, ASitzY + LSitz);
      FCanvas.DrawImageRect(LImage, LRectF);
    end
    else if ASpalte = 0 then begin
      LImage := TSkImage.MakeFromEncodedFile(ICONS + 'Icon_treppe_L.png');
      LRectF := TRectF.Create(ASitzX, ASitzY, ASitzX + 2 * LSitz, ASitzY + LSitz);
      FCanvas.DrawImageRect(LImage, LRectF);
    end
    else if ASpalte = 3 then begin
      LImage := TSkImage.MakeFromEncodedFile(ICONS + 'Icon_treppe.png');
      LRectF := TRectF.Create(ASitzX, ASitzY, ASitzX + 2 * LSitz, ASitzY + LSitz);
      FCanvas.DrawImageRect(LImage, LRectF);
    end;
  end; // procedure lokEinstieg

  procedure lokUmriss;
  var
    LFuenf, LZwei, LWidth: single;
    LRectF: TRectF;
  begin
    LFuenf := 5 * FZoom;
    LZwei := 2 * FZoom;
    LWidth := 55 * FZoom;
    LRectF.Top := LTop;
    LRectF.Left := LLeft;
    LRectF.Width := LWidth;
    LRectF.Height := LDrawHeight;
    FCanvas.DrawRoundRect(LREctF, 5, 5, FDrawPaint);
  end; // procedure lokUmriss

  procedure lokBuchstaben;
  var
    LSpalte: integer;
    LSitzX: single;
  begin
    for LSpalte := 0 to 4 do begin
      LSitzX := LLeft + (LSpalte * (SITZ + ZWI) + 2 * ZWI) * FZoom;
      case LSpalte of
        0: lokTextZentriert(LSitzX, LTop, SITZ * FZoom, 15, 'A');
        1: lokTextZentriert(LSitzX, LTop, SITZ * FZoom, 15, 'B');
        3: lokTextZentriert(LSitzX, LTop, SITZ * FZoom, 15, 'C');
        4: lokTextZentriert(LSitzX, LTop, SITZ * FZoom, 15, 'D');
      end;
    end;
    LTop := LTop + SITZ * FZoom;
  end; // procedure lokBuchstaben

  procedure lokBusSitze;
  var
    LReihe, LSpalte, ix: integer;
    LSitzX, LSitzY, LDrawWidth2: single;
  begin
    LDrawHeight := (LRowCount * 10 + 10) * FZoom;
    if (LTop = 0) and (LBottom > 0) then
      LTop := LBottom - LDrawHeight;
    lokTextZentriert(LLeft, LTop, 55 * FZoom, 15, 'Bus-Sitzplan', TAlphaColorRec.Darkblue);
    LTop := LTop + SITZ * FZoom;
    lokBuchstaben;
    FDrawPaint.StrokeWidth := FZoom;
    lokUmriss;
    FDrawPaint.StrokeWidth := 0.2 * FZoom;
//    FDrawPaint.StrokeWidth := 0.4 * FZoom;
    LSitz := SITZ * FZoom;
    L80 := LSitz * 0.85;
    for LReihe := 0 to LRowCount - 1 do begin
      LSitzY := LTop + ((LReihe + 1) * (SITZ + ZWI)) * FZoom;
      for LSpalte := 0 to 4 do begin
        LSitzX := LLeft + (LSpalte * (SITZ + ZWI) + 2 * ZWI) * FZoom;
        LPlatz := LBus[LReihe, LSpalte];
        ix := LPreisListe.IndexOf(FormatFloat('0.00', LPlatz.preis));
        if ix = -1 then
          ix := 0;
        LFillPaint.Color := TAlphaColor(LPreisListe.Objects[ix]);
        case LPlatz.status of
          'G', 'Z', 'W': lokBusSitz(LReihe, LSpalte, LSitzX, LSitzY, '',
              LFontSize, true, 'Icon_nicht-reservierbar.png');
          'R': lokBusSitz(LReihe, LSpalte, LSitzX, LSitzY,
              IfThen(LFmtString = '', '', FormatFloat(LFmtString, LPlatz.preis)),
              LFontSize, true);
          'L': lokBusSitz(LReihe, LSpalte, LSitzX, LSitzY, '',
              LFontSize, true, 'Icon_reiseleiter.png');
          'T': if LSpalte in [0, 3] then
              lokIcon(LSitzX, LSitzY, 'Icon_toilette.png', true);
          'K': if LSpalte in [0, 3] then
              lokIcon(LSitzX, LSitzY, 'Icon_kueche.png', true);
          'F': if LSpalte in [0, 3] then
              lokBusSitz(LReihe, LSpalte, LSitzX + LSitz * 0.6 , LSitzY, '',
                  LFontSize, true, 'Icon_fahrer.png');
          'E', 'S': if LSpalte in [0, 3] then
              lokEinstieg(LSpalte, LSitzX, LSitzY, false);
          'J': if LSpalte in [0, 3] then
              lokEinstieg(LSpalte, LSitzX, LSitzY, true);
          'O': if LSpalte in [1, 3] then
              lokIcon(LSitzX, LSitzY, 'Icon_wendeltreppe.png')
              else if LSpalte = 2 then
                lokTextZentriert(LSitzX - 2 * SITZ * FZoom, LSitzY,
                    5 * SITZ * FZoom, 12, 'Oberdeck');
          'A': if LReihe > 0 then
              lokTextZentriert(LSitzX, LSitzY, SITZ * FZoom, 15, IntToStr(LReihe));
        end;
      end;
    end;
    LTop := LTop + LDrawHeight + 4;
    lokBuchstaben;
  end; // procedure lokBusSitze

  procedure lokPreisFarben;
  var
    i: integer;
    LColor : TAlphaColor;
  begin
    LPreisListe.CustomSort(PreisListenSort);
    for i := 0 to LPreisListe.Count - 1 do begin
      if StrToCurrDef(LPreisListe[i], 0) = 0 then
        LColor := TAlphaColorRec.Alpha
            or FindParamIntegerReplaced('cl_0', $FFFFFF)
      else
        LColor := TAlphaColorRec.Alpha
            or FindParamIntegerReplaced('cl_' + IntToStr(i + 1), $FFFF00);
      LPreisListe.Objects[i] := TObject(LColor);
    end;
  end; // procedure lokPreisFarben

  procedure lokBusDaten;
  var
    LSql, LPreis, LBafConName, LName: string;
    LData: TDataSet;
    LReihe, LSpalteNum: integer;
    LSpalte: Char;
  begin
    LSql := FInter.GetSqlAndClear(1);
    LBafConName := FindParamStringReplacedLower('db', DC_DEFAULT);
    LName := FInter.Name + '~' + LBafConName;
    SqlAndParams(LBafConName, LName, LSql);
    LData := dataMain.QueryOpen(LBafConName, LName);
    LRowCount := 0;
    while not LData.Eof do begin
      FInter.DebugDbRow(LData);
      LReihe := LData.FieldByName('reihe').AsInteger;
      LSpalte := (LData.FieldByName('spalte').AsString + ' ')[1];
      case LSpalte of
        'A': LSpalteNum := 0;
        'B': LSpalteNum := 1;
        'M': LSpalteNum := 2;
        'C': LSpalteNum := 3;
        'D': LSpalteNum := 4;
      end;
      if (LReihe in [0..17]) and (LSpalteNum in [0..4]) then begin
        LBus[LReihe, LSpalteNum].platz := IntToStr(LReihe) + LSpalte;
        LBus[LReihe, LSpalteNum].status
            := (LData.FieldByName('status').AsString + ' ')[1];
        LBus[LReihe, LSpalteNum].ausrichtung
            := (LData.FieldByName('ausrichtung').AsString + ' ')[1];
        LBus[LReihe, LSpalteNum].preis := LData.FieldByName('preis').AsCurrency;
        LPreis := FormatFloat('0.00', LBus[LReihe, LSpalteNum].preis);
        if LPreisListe.IndexOf(LPreis) = -1 then
          LPreisListe.Add(LPreis);
        LRowCount := System.Math.Max(LRowCount, LReihe + 1);
        LData.Next;
      end;
    end; // while
  end; // procedure lokBusDaten;

begin
  LPreisListe := TStringList.Create;
  try
    LLeft := FindParamSingleReplaced('l', 150) * FZoom;
    LTop := FindParamSingleReplaced('t', 0) * FZoom;
    LBottom := FindParamSingleReplaced('b', 0) * FZoom;
    LFontSize := FindParamIntegerReplaced('fs', 5);
    LFmtString := FindParamStringReplaced('fmt', '0.00');
    LPreisListe.Add('0,00');
    FDrawPaint.Color := TAlphaColorRec.Black;
    FDrawPaint.StrokeWidth := 1;
    FDrawPaint.Style := TSkPaintStyle.Stroke;
    LFillPaint := TSkPaint.Create;
    LFillPaint.Color := TAlphaColorRec.White;
    LFillPaint.Style := TSkPaintStyle.Fill;
    LFillPaintGray := TSkPaint.Create;
    LFillPaintGray.Color := TAlphaColorRec.Gray;
    LFillPaintGray.Style := TSkPaintStyle.Fill;
    FFontPaint.Color := TAlphaColorRec.Black;
    LEinstiegPaint := TSkPaint.Create;
    LEinstiegPaint.Color := TAlphaColorRec.Silver;
    LEinstiegPaint.Style := TSkPaintStyle.Fill;
    lokBusDaten;
    lokPreisFarben;
    lokBusSitze;
    FY := FY + 615 * LScale;
  finally
    LPreisListe.Free;
  end;
// procedure TBafPdfModule.PdfVBus
end;

procedure TBafPdfModule.PdfVBusNamen;
var
  LX, LY, LWidth, LHeight, LSitzHeight, LSitzWidth, LFontSize: single;
  LRectF: TRectF;
  LRowMax: integer;

  procedure lokParams;
  begin
    LX := FindParamSingleReplaced('x', 0) * FZoom;
    LY := FindParamSingleReplaced('y', 0) * FZoom;
    LWidth := FindParamSingleReplaced('w', 0) * FZoom;
    LHeight := FindParamSingleReplaced('h', 0) * FZoom;
    LRectF.Left := LX;
    LRectF.Top:= LY;
    LRectF.Width := LWidth;
    LRectF.Height := LHeight;
    FDrawPaint.Color := TAlphaColorRec.Gray;
    FDrawPaint.StrokeWidth := 3;
    FCanvas.DrawRoundRect(LRectF, 7, 7, FDrawPaint);
    FDrawPaint.Color := TAlphaColorRec.Black;
    FDrawPaint.StrokeWidth := 1;
    LRowMax := FindParamIntegerReplaced('max', 14);
    LSitzHeight := 0.82 * (LHeight / (LRowMax + 1));
    LSitzWidth := LWidth / 5.6;
    LFontSize := FindParamSingleReplaced('s', 15);
  end; // procedure lokParams

  procedure lokZeile(AText: string; ARectF: TRectF);
  var
    LSize: single;
    LParagraph: ISkParagraph;
    LBuilder: ISkParagraphBuilder;
    LParagraphStyle: ISkParagraphStyle;
    LTextStyle: ISkTextStyle;

    procedure lokPaint(APara: string);
    var
      LText: string;
      p: integer;
    begin
      LParagraphStyle := TSkParagraphStyle.Create;
      LParagraphStyle.TextAlign := TSkTextAlign.Center;
      LBuilder := TSkParagraphBuilder.Create(LParagraphStyle);
      LTextStyle := TSkTextStyle.Create;
      LTextStyle.SetFontSize(LSize);
      LTextStyle.Color := TAlphaColorRec.Black;
      LBuilder.PushStyle(LTextStyle);
      LBuilder.AddText(APara);
      LParagraph := LBuilder.Build;
      LParagraph.Layout(ARectF.Width);
    end; // procedure lokPaint

  begin
    ARectF.Inflate(- ARectF.Height * 0.05, ARectF.Height * 0.05);
    LSize := LFontSize;
    lokPaint(AText);
    while (LParagraph.Height > ARectF.Height) and (ARectF.Height > 5) do begin
      LSize := LSize * 0.95;
      lokPaint(AText);
    end;
    LParagraph.Paint(FCanvas, ARectF.Left, ARectF.Top);
  end; // procedure lokZeile

  procedure lokData;
  var
    LSql, LPreis, LBafConName, LName: string;
    LData: TDataSet;
    LReihe, LSpalteNum: integer;
    LSpalte, LStatus: Char;

    procedure lokSitz(AZeile2, AZeile3: string);
    var
      LSitzX, LSitzY: single;
    begin
      LSitzX := LX + LSpalteNum * LSitzWidth + 0.1 * LSitzWidth * (LSpalteNum + 1);
      LSitzY := LY + (LRowMax - LReihe) * LSitzHeight + 0.2 * LSitzHeight * (1 + LRowMax - LReihe);
      LRectF.Left := LSitzX;
      LRectF.Top:= LSitzY;
      LRectF.Width := LSitzWidth;
      LRectF.Height := LSitzHeight;
      FCanvas.DrawRoundRect(LRectF, 1, 1, FDrawPaint);
      LRectF.Height := LSitzHeight / 3;
      lokZeile(IntToStr(LReihe) + LSpalte + LData.FieldByName('rz').AsString, LRectF);
      LRectF.Top := LRectF.Top + 0.28 * LSitzHeight;
      LRectF.Height := LSitzHeight / 3;
      lokZeile(AZeile2, LRectF);
      LRectF.Top := LRectF.Top + 0.31 * LSitzHeight;
      LRectF.Height := LSitzHeight / 3;
      lokZeile(AZeile3, LRectF);
    end; // procedure lokSitz

    procedure lokPlatz(AZeile: string; ARand: boolean);
    var
      LSitzX, LSitzY: single;
    begin
      if LSpalteNum in [0, 3]  then begin
        LSitzX := LX + LSpalteNum * LSitzWidth + 0.1 * LSitzWidth * (LSpalteNum + 1);
        LSitzY := LY + (LRowMax - LReihe) * LSitzHeight + 0.2 * LSitzHeight * (1 + LRowMax - LReihe);
        LRectF.Left := LSitzX;
        LRectF.Top:= LSitzY;
        LRectF.Width := 2 * LSitzWidth + 0.1 * LSitzWidth;
        LRectF.Height := LSitzHeight;
        if ARand then
          FCanvas.DrawRoundRect(LRectF, 1, 1, FDrawPaint);
        LRectF.Top := LRectF.Top + 0.2 * LSitzHeight;
        lokZeile(AZeile, LRectF);
      end;
    end; // procedure lokSitz

  begin
    LSql := FInter.GetSqlAndClear(1);
    LBafConName := FindParamStringReplacedLower('db', DC_DEFAULT);
    LName := FInter.Name + '~' + LBafConName;
    SqlAndParams(LBafConName, LName, LSql);
    LData := dataMain.QueryOpen(LBafConName, LName);
    while not LData.Eof do begin
      FInter.DebugDbRow(LData);
      LReihe := LData.FieldByName('reihe').AsInteger;
      LSpalte := (LData.FieldByName('spalte').AsString + ' ')[1];
      case LSpalte of
        'A': LSpalteNum := 4;
        'B': LSpalteNum := 3;
        'M': LSpalteNum := 2;
        'C': LSpalteNum := 1;
        'D': LSpalteNum := 0;
      end;
      if (LReihe in [0..17]) and (LSpalteNum in [0..4]) then begin
        LStatus := (LData.FieldByName('status').AsString + ' ')[1];
        case LStatus of
          'R', 'W': lokSitz(LData.FieldByName('nachname').AsString,
              LData.FieldByName('vorname').AsString);
          'L': lokSitz('Reiseleiter', '');
          'G': lokSitz('gesperrt', '');
          'Z': lokSitz('2. Fahrer', '');
          'F': lokPlatz('Fahrer', false);
          'E': lokPlatz('Einstieg', false);
          'K': lokPlatz('Küche', true);
          'T': lokPlatz('Toilette', true);
          'J': lokPlatz('Einstieg / Toilette', false);
          'S': lokPlatz('Treppe', false);
          'O': lokPlatz('Oberdeck / Wendeltreppe', false);
        end;
        LData.Next;
      end;
    end; // while
  end; // procedure lokData

begin
  if FindParamBooleanReplaced('cnd', true) then begin
    lokParams;
    lokData;

  end;
// procedure TBafPdfModule.PdfVBusNamen
end;

procedure TBafPdfModule.PrintCell(ACell: TBafSgCell; ACol: integer;
    APdfGridColumn: TBafPdfGridColumn);
var
  LRight: single;
  i: integer;
  LPdfGridColumn2: TBafPdfGridColumn;
begin
  LRight := APdfGridColumn.Right * FZoom - 6;
  for i := 1 to ACell.ColSpan - 1 do begin
    LPdfGridColumn2 := (FColumns[ACol + i] as TBafPdfGridColumn);
    if LPdfGridColumn2.Page = APdfGridColumn.Page then
      LRight := LPdfGridColumn2.Right * FZoom - 6
    else
      Break;
  end;
 FCanvas.DrawSimpleText(ACell.Text, (APdfGridColumn.Left) * FZoom,
     FY, FFont, FFontPaint);
end;

procedure TBafPdfModule.InitPage;
begin
  FPageScale := 0.29;
  if FLandscape then begin
//    FPageSize.Width := 297;
//    FPageSize.Height := 210;
    FPageMarginLeft := 15;
    FPageMarginRight := 15;
    FPageMarginTop := 25;
    FPageMarginBottom := 15;
  end
  else begin
//    FPageSize.Width := 210;
//    FPageSize.Height := 297;
    FPageMarginLeft := 25;
    FPageMarginRight := 15;
    FPageMarginTop := 15;
    FPageMarginBottom := 15;
  end;
  FPageWidthUse := (FPageSize.Width - FPageMarginLeft - FPageMarginRight) / FZoom;
end;

function TBafPdfModule.InterpretLine(AExecInter: TBafCustomInterpreter): boolean;
var
  LInter: TBafCustomInterpreter;
begin
  result := false;
  LInter := FExecInter;
  try
    FExecInter := AExecInter;

    result := true;
    if FExecInter.LineF = '#pdf_start' then PdfStart                              // starts creation of a PDF
    else if FExecInter.LineF = '#pdf_stop' then PdfStop(false)                    // stops the creation an saves the file
    else if FExecInter.LineF = '#pdf_text' then PdfLine(true)                     // draw a line, with LineFeed
    else if FExecInter.LineF = '#pdf_texto' then PdfLine(false)                   // draw a line, without LineFeed
    else if FExecInter.LineF = '#pdf_font' then PdfFont                           // sets the font
    else if FExecInter.LineF = '#pdf_sety' then PdfSetY                           // sets the Y position
    else if FExecInter.LineF = '#pdf_checknewline' then PdfCheckNewLine           // checks for the lower border of the page
    else if FExecInter.LineF = '#pdf_insertpic' then PdfInsertPic                 // loads a picture from file and inserts it
    else if FExecInter.LineF = '#pdf_newpage' then PdfAddPage                     // creates a new page
    else if FExecInter.LineF = '#pdf_newcol' then PdfAddCol                       // creates a new column
    else if FExecInter.LineF = '#pdf_execsub' then PdfExecSub                     // executes a subroutine
    else if FExecInter.LineF = '#pdf_multi' then PdfMultiline                     // draw multiline text
    else if FExecInter.LineF = '#pdf_multibb' then PdfMultilineBB2                // draw multiline text with formatting codes
    else if FExecInter.LineF = '#pdf_line' then PdfDrawLine                       // draw a line
    else if FExecInter.LineF = '#pdf_coldef' then PdfColfDef                      // defines columns
    else if FExecInter.LineF = '#pdf_drawdef' then PdfDrawDef                     // settings for #pdf_rect and #pdf_line
    else if FExecInter.LineF = '#pdf_rect' then PdfDrawRectangle                  // draw rect, roundrect or oval
    else if FExecInter.LineF = '#pdf_gdef' then PdfGridDef                        // Defines a grid
    else if FExecInter.LineF = '#pdf_grow' then PdfGridRow                        // Adds a row to a grid
    else if FExecInter.LineF = '#pdf_gend' then PdfGridEnd                        // Ends a grid


    {$IFDEF with_zint}
    else if FExecInter.LineF = '#pdf_createbarcode' then PdfCreateBarcode          // creates a barcode to insert with #pdfinsertpic
    {$ENDIF}

    else if FExecInter.LineF = '#pdf_bus' then PdfBus                              // create a bus plan für trendtours
    else if FExecInter.LineF = '#pdf_vbus' then PdfVBus                            // create a bus plan für trendtours
    else if FExecInter.LineF = '#pdf_vbus_namen' then PdfVBusNamen                 // create a bus plan für trendtours
    else if FExecInter.LineF = '#pdf_textmax' then PdfMaxSizeText                  // Paints a Text in max Size


    else result := false;
  finally
    FExecInter := LInter;
  end;

end;

procedure TBafPdfModule.MakeColumns;
var
  LRow, LCol, LPage, LMaxColSpan, i: integer;
  LPdfGridColumn: TBafPdfGridColumn;
  LCell: TBafSgCell;
  LLeftPos, LWidthLeft, LCalcedWidth, LCalcedWidthSpan: single;

  function lokColWidth(ACol: integer): single;
  var
    LColumn: TBafSgColumn;
  begin
    LColumn := FGrid.Columns.Items[ACol];
    if LColumn.CellType in [ctButton,  ctGuid, ctLink] then
      result := 0
    else
      result := LColumn.Width * FPageScale + 6;
  end; // function lokColWidth

begin
  LPage := 1;
  LLeftPos := FPageMarginLeft;
  LWidthLeft := FPageWidthUse;
  for LCol := 0 to FGrid.Columns.Count - 1 do begin
    LCalcedWidth := lokColWidth(LCol);
    LMaxColSpan := 1;
    for LRow := 0 to FGrid.RowCount(rtHeader) - 1 do begin
      LCell := FGrid.Cells[rtHeader, LCol, LRow];
      LMaxColSpan := System.Math.Max(LMaxColSpan, LCell.ColSpan);
    end;
    LCalcedWidthSpan := 0;
    for i := 0 to LMaxColSpan - 1 do
      LCalcedWidthSpan := LCalcedWidthSpan + lokColWidth(i);
    if ((LCalcedWidthSpan > LWidthLeft) and (LCalcedWidthSpan < FPageWidthUse))
        or (LCalcedWidth > LWidthLeft) then begin
      inc(LPage);
      LLeftPos := FPageMarginLeft;
      LWidthLeft := FPageWidthUse;
    end;
    if LCalcedWidth > 1 then begin
      LPdfGridColumn := TBafPdfGridColumn.Create;
      LPdfGridColumn.Index := LCol;
      LPdfGridColumn.Page := LPage;
      LPdfGridColumn.Left := LLeftPos;
      LPdfGridColumn.Right := LLeftPos + LCalcedWidth;
      LWidthLeft := LWidthLeft - LCalcedWidth;
      LLeftPos := LPdfGridColumn.Right;
      FColumns.Add(LPdfGridColumn);
    end;
  end;
  FPagesPerRow := LPage;
// procedure TBafPdfModule.MakeColumns
end;

procedure TBafPdfModule.PrintHeader(APage, ARow: integer);
var
  LCol, LRow, ix: integer;
  LPdfGridColumn: TBafPdfGridColumn;
  LCell: TBafSgCell;
  s: string;
  LEinr: single;
begin
  if (APage > 1) or (ARow > 0)  then
    PdfAddPage;
  FColNum := 0;
  FFont.Embolden := true;
  for LRow := 0 to FGrid.RowCount(rtHeader) - 1 do begin
    ix := FGrid.RowCount(rtHeader);
    for LCol := 0 to FColumns.Count - 1 do begin
      LPdfGridColumn := (FColumns[LCol] as TBafPdfGridColumn);
      if LPdfGridColumn.Page = APage then begin
        LCell := FGrid.Cells[rtHeader, LPdfGridColumn.Index, LRow];
        PrintCell(LCell, LCol, LPdfGridColumn);

      end
      else if LPdfGridColumn.Page > APage then
        Break;
    end;
    FY := FY + 1.2 * FLineHeight;
  end;
  FFont.Embolden := false;
  FFont.Size := 8;
  s := IntToStr(FPage);
  LEinr := CalcTextLeft(s, FPageSize.Width - 10, taRightJustify);
  FCanvas.DrawSimpleText(s, LEinr, FPageSize.Height - 10, FFont, FFontPaint);
  FFont.Size := 10;
end;

procedure TBafPdfModule.PrintRows(APage, AStart: integer; var ALast: integer);
var
  LCol: integer;
  LPdfGridColumn: TBafPdfGridColumn;
  LCell: TBafSgCell;
begin
  while (AStart < FGrid.RowCount(rtData))
      and (FY < (FPageSize.Height - FPageMarginBottom * FZoom)) do begin
    for LCol := 0 to FColumns.Count - 1 do begin
      LPdfGridColumn := (FColumns[LCol] as TBafPdfGridColumn);
      if LPdfGridColumn.Page = APage then begin
        LCell := FGrid.Cells[rtData, LPdfGridColumn.Index, AStart];
        PrintCell(LCell, LCol, LPdfGridColumn);
        ALast := AStart;
      end
      else if LPdfGridColumn.Page > APage then
        Break;
    end;
    FY := FY + FLineHeight;
    inc(AStart);
  end;
end;

function TBafPdfModule.OpenFileDialog(var AFileName: string): boolean;
var
  LDialog: TSaveDialog;
begin
  result := false;
  LDialog := TSaveDialog.Create(nil);
  try
    LDialog.Filter := 'PDF-Dateien *.pdf|*.pdf|Alle Dateien *.*|*.*';
    LDialog.DefaultExt := 'pdf';
    result := LDialog.Execute;
    if result then
      AFileName := LDialog.FileName;
  finally
    LDialog.Free;
  end;
end;

end.


