ONO::Lib::PDF::Elements::Grid

package ONO::Lib::PDF::Elements::Grid;
################################################################################
# COPYRIGHT / LICENSE #
################################################################################
#
# This file is part of the ONO Software Project.
#
# Copyright (C) 2000-2025 Jos KIRPS [ www.kirps.com | jos_AT_kirps_DOT_com ]
# and The Joopita Project [ www.joopita.org | contact_AT_joopita_DOT_com ]
#
# This file, as well as other parts of the ONO Software Project or related
# elements, are FREE SOFTWARE available under the ARTISTIC LICENSE 2.0.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# For the full license, see /ono/osr/license/LICENSE.txt, or write to
# jos_AT_kirps_DOT_com or contact_AT_joopita_DOT_com.
#
################################################################################
# END OF COPYRIGHT / LICENSE, HERE COMES THE CODE ... #
################################################################################

use strict;

use ONO::Lib::PDF::Draw;
use ONO::Lib::Image::Canvas::Draw;

#: This module generates specific PDF content.

sub grid {

my (
$self,
$canvas,
$x1,
$y1,
$x2,
$y2,
$spacing,
$weight_inner,
$weight_outer,
$outset,
$color,
$switches,
$data_ref,
$color_line,
$font_ref,
) = @_;

#: This generates a grid.
#:
#: spacing is required -> integers draw a squared grid
#: -> "x:y" allows for grids that are not square
#: -> "x/y" will draw a grid with x cols and y rows (spacing will thus be calculated)
#:
#: outset (optional) allows to draw lines beyond the actual grid (top, bottom, left & right)
#:
#: color is the background of the entire grid -> "g/r/c" will colorize background, top row, left col,
#: creating a spreadsheet-like grid (all optional),
#: top row has priority (always on top of left grid)
#:
#: data_ref -> array containing data to be filled into the created grid boxes,
#: will simply fill from left to right, top to bottom
#:
#: -A autocrop, will limit the global size to spacing values (otherwise the result may be larger than
#: the indicated grid size)
#: -C comma in EU format (replaces commas in ALL cell data)
#: -f font options enabled (also disables default center text, required for font_ref)
#: -l light (combinable with -L)
#: -L even lighter (combinable with -l)
#: -m millimeter mode (only works if spacing = 1, will highlight 5 mm grid)
#: -M math symbol processing
#: -X clear all data that's not in the header row/col

my $DEBUG;

if ($spacing) {

eval "use PDF::Reuse";
if (!$@) {

my ($whilecounter,$disable_size_fix,@colors,$cols,$rows,$update_font_color);

my ($draw_x,$draw_y) = ($x1,$y1);
my ($spac_x,$spac_y) = ($spacing,$spacing);
if ($spacing =~ m~^(.*?):(.*?)$~) {
($spac_x,$spac_y) = ($1,$2);
}
if ($spacing =~ m~^(.*?)/(.*?)$~) {
my ($one,$two) = ($1,$2);
if ($one && $two) {
$spac_x = ($x2-$x1)/$one;
$spac_y = ($y2-$y1)/$two;
$disable_size_fix++;
}
}

$DEBUG .= qq~hello grid, ori = $draw_x,$draw_y, spacing = $spac_x,$spac_y, ~;

my $COLOR_LINE = "0:0:0:0";
if ($color_line) {
$COLOR_LINE = $color_line;
}
if ($spacing == 1 && $switches =~ /m/) {
if (!$color_line) {
$color_line = "0:0:0:0";
}
$COLOR_LINE = ONO::Lib::PDF::Draw->color_calc($color_line,30);
}
if ($switches =~ /l/) {
$COLOR_LINE = "0:70:70:70";
$color_line = ONO::Lib::PDF::Draw->color_calc($color_line,60);
}
if ($switches =~ /L/) {
$COLOR_LINE = "0:140:140:140";
$color_line = ONO::Lib::PDF::Draw->color_calc($color_line,60);
}
if ($switches =~ /l/ && $switches =~ /L/) {
$COLOR_LINE = "0:210:210:210";
$color_line = ONO::Lib::PDF::Draw->color_calc($color_line,50);
}

if (!$disable_size_fix) {

$DEBUG .= qq~size fixing for $x2,$y2 = ~;

# make sure that $x2 and $y2 are multiples of spacing

my ($ori_x,$ori_y) = ($x2,$y2);
my ($test_x,$test_y) = ($spac_x,$spac_y);

if ($spacing == 1 && $switches =~ /m/) {
($test_x,$test_y) = (5,5);
}

if ($test_x > 0) {
my $test = $x1;
if (($x2-$x1)%$test_x != 0) {
while ($test < $x2 && $whilecounter < 4096) {
$whilecounter++;
$test = $test + $test_x;
}
$x2 = $test;
}
}

if ($test_y > 0) {
my $test = $y1;
if (($y2-$y1)%$test_y != 0) {
while ($test < $y2 && $whilecounter < 4096) {
$whilecounter++;
$test = $test + $test_y;
}
$y2 = $test;
}
}
if ($switches =~ /A/) {
if ($x2 > $ori_x) {
$x2 = $x2-$test_x;
}
if ($y2 > $ori_y) {
$y2 = $y2-$test_y;
}
}

$DEBUG .= qq~$x2,$y2, ~;

}

# colors

if ($color) {

$DEBUG .= "input color = $color, ";

@colors = ($color);
if ($color =~ /\//) {
@colors = split(/\//,$color);
}
ONO::Lib::PDF::Draw->rect($canvas,$x1,$y1,$x2,$y2,0,"",$colors[0]);
if ($colors[2]) {
ONO::Lib::PDF::Draw->rect($canvas,$x1,$y1,$x1+$spac_x,$y2,0,"",$colors[2]);
}
if ($colors[1]) {
ONO::Lib::PDF::Draw->rect($canvas,$x1,$y1,$x2,$y1+$spac_y,0,"",$colors[1]);
}
}

# draw the grid

while ($draw_y < $y2+1 && $whilecounter < 4096) {

ONO::Lib::PDF::Draw->line($canvas,$x1-$outset-$weight_inner/6,$draw_y,$x2+$outset+$weight_inner/6,$draw_y,$weight_inner,$COLOR_LINE);
$draw_y = $draw_y + $spac_y;
$whilecounter++;
$rows++;

}

while ($draw_x < $x2+1 && $whilecounter < 4096) {

ONO::Lib::PDF::Draw->line($canvas,$draw_x,$y1-$outset-$weight_inner/6,$draw_x,$y2+$outset+$weight_inner/6,$weight_inner,$COLOR_LINE);
$draw_x = $draw_x + $spac_x;
$whilecounter++;
$cols++;

}

if ($spacing == 1 && $switches =~ /m/) {

my ($draw_x,$draw_y) = ($x1,$y1);

while ($draw_y < $y2+1 && $whilecounter < 4096) {

ONO::Lib::PDF::Draw->line($canvas,$x1-$outset,$draw_y,$x2+$outset,$draw_y,$weight_inner*2,$color_line);
$draw_y = $draw_y + 5;
$whilecounter++;
$rows++;

}

while ($draw_x < $x2+1 && $whilecounter < 4096) {

ONO::Lib::PDF::Draw->line($canvas,$draw_x,$y1-$outset,$draw_x,$y2+$outset,$weight_inner*2,$color_line);
$draw_x = $draw_x + 5;
$whilecounter++;
$cols++;

}

}

# outer border

if ($weight_outer > 0 && $weight_outer != $weight_inner) {

ONO::Lib::PDF::Draw->rect($canvas,$x1,$y1,$x2,$y2,$weight_outer,$COLOR_LINE);

}

# fill in data

if ($data_ref) {

$DEBUG .= "using table content data, ";

my @data = @$data_ref;
my $data_counter;

my %font;
my $FONT = "H";

if ($switches =~ /f/ && $font_ref) {
%font = %$font_ref;
$DEBUG .= "using custom font settings ($font{'align'},$font{'size'},$font{'type'},$font{'color'}), ";

if ($font{'type'} || $font{'size'}) {
if ($font{'type'} =~ /b/) {
$FONT = "HB";
}
if ($font{'type'} =~ /i/) {
$FONT = "HO";
if ($font{'type'} =~ /b/) {
$FONT = "HBO";
}
}
ONO::Lib::PDF::Draw->font($FONT,$font{'size'});
$update_font_color++;
}
if ($font{'color'}) {
ONO::Lib::PDF::Draw->color($font{'color'});
$update_font_color++;
}

}

for (my $r = 0; $r < $rows-1; $r++) {
for (my $c = 0; $c < $cols-1; $c++) {

if ($switches !~ /X/ || $r == 0 || $c == 0) {

if ($switches =~ /C/) {
$data[$data_counter] =~ s~\.~\,~g;
}

if ($switches =~ /M/ && $data[$data_counter] =~ /^(\+|\-|x|\/|add|sub|mul|div)$/) {

ONO::Lib::PDF::Draw->text_math_symbol($canvas,$x1+$c*$spac_x+$spac_x/2,$y1+$r*$spac_y+$spac_y*0.52,2.5,$data[$data_counter]);

} else {

my @fontdata = (
$x1+$c*$spac_x+$spac_x/2,
$y1+$r*$spac_y+$spac_y*0.66,
$data[$data_counter],
"c",
);

if ($switches =~ /f/) {

@fontdata = (
$x1+$c*$spac_x+2,
$y1+$r*$spac_y+$spac_y*0.66,
$data[$data_counter],
"",
);

if ($font{'align'} eq "center") {
@fontdata = (
$x1+$c*$spac_x+$spac_x/2,
$y1+$r*$spac_y+$spac_y*0.66,
$data[$data_counter],
"c",
);
}

if ($font{'align'} eq "right") {
@fontdata = (
$x1+$c*$spac_x+$spac_x-2,
$y1+$r*$spac_y+$spac_y*0.66,
$data[$data_counter],
"r",
);
}

}

if ($font{'type_cola'} =~ /(b|i)/) {
my $FONT2 = $FONT;
if ($c == 0 && ($r || !$font{'type_row0'})) {
if ($font{'type_cola'} =~ /i/) {
$FONT2 = "HO";
}
if ($font{'type_cola'} =~ /b/) {
$FONT2 = "HB";
if ($font{'type_cola'} =~ /i/) {
$FONT2 = "HBO";
}
}
}
ONO::Lib::PDF::Draw->font($FONT2,$font{'size'});
$update_font_color++;
}

if ($font{'type_row0'} =~ /(b|i)/ && $r == 0) {
my $FONT2 = $FONT;
if ($r == 0) {
if ($font{'type_row0'} =~ /i/) {
$FONT2 = "HO";
}
if ($font{'type_row0'} =~ /b/) {
$FONT2 = "HB";
if ($font{'type_row0'} =~ /i/) {
$FONT2 = "HBO";
}
}
}
ONO::Lib::PDF::Draw->font($FONT2,$font{'size'});
$update_font_color++;
}

my $COLOR;

if ($font{'color'} && ($font{'color_row0'} || $font{'color_cola'})) {
$COLOR = $font{'color'};
}
if ($c == 0 && $font{'color_cola'}) {
$COLOR = $font{'color_cola'};
}
if ($r == 0 && $font{'color_row0'}) {
$COLOR = $font{'color_row0'};
}
if ($COLOR) {
ONO::Lib::PDF::Draw->color($COLOR);
}

ONO::Lib::PDF::Draw->text($canvas,@fontdata);

}

}
$data_counter++;

}
}

if ($switches =~ /f/) {

if ($font{'size'} || $font{'type'}) {
ONO::Lib::PDF::Draw->font('H',12);
$update_font_color = 0;
}
if ($font{'color'}) {
ONO::Lib::PDF::Draw->color();
$update_font_color = 0;
}

}

}

if ($update_font_color) {
ONO::Lib::PDF::Draw->font('H',12);
ONO::Lib::PDF::Draw->color();
}

# done

}
}

return $DEBUG;

}

###############################################################################
# end of script
###############################################################################

1;

__END__