xref: /webtrees/app/Report/ReportHtmlTextbox.php (revision df27497a949ee94233b78915e33f253447a14e62)
1<?php
2
3/**
4 * webtrees: online genealogy
5 * Copyright (C) 2019 webtrees development team
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18declare(strict_types=1);
19
20namespace Fisharebest\Webtrees\Report;
21
22/**
23 * Class ReportHtmlTextbox
24 */
25class ReportHtmlTextbox extends ReportBaseTextbox
26{
27    /**
28     * Render the elements.
29     *
30     * @param ReportHtml $renderer
31     *
32     * @return void
33     */
34    public function render($renderer)
35    {
36        // checkFootnote
37        $newelements      = [];
38        $lastelement      = [];
39        $footnote_element = [];
40        // Element counter
41        $cE = count($this->elements);
42        //-- collapse duplicate elements
43        for ($i = 0; $i < $cE; $i++) {
44            $element = $this->elements[$i];
45            if ($element instanceof ReportBaseElement) {
46                if ($element instanceof ReportBaseText) {
47                    if (!empty($footnote_element)) {
48                        ksort($footnote_element);
49                        foreach ($footnote_element as $links) {
50                            $newelements[] = $links;
51                        }
52                        $footnote_element = [];
53                    }
54                    if (empty($lastelement)) {
55                        $lastelement = $element;
56                    } else {
57                        // Checking if the Text has the same style
58                        if ($element->getStyleName() === $lastelement->getStyleName()) {
59                            $lastelement->addText(str_replace("\n", '<br>', $element->getValue()));
60                        } elseif (!empty($lastelement)) {
61                            $newelements[] = $lastelement;
62                            $lastelement   = $element;
63                        }
64                    }
65                } elseif ($element instanceof ReportHtmlFootnote) {
66                    // Check if the Footnote has been set with it’s link number
67                    $renderer->checkFootnote($element);
68                    // Save first the last element if any
69                    if (!empty($lastelement)) {
70                        $newelements[] = $lastelement;
71                        $lastelement   = [];
72                    }
73                    // Save the Footnote with it’s link number as key for sorting later
74                    $footnote_element[$element->num] = $element;
75                } elseif (trim($element->getValue()) !== '') {
76                    // Do not keep empty footnotes
77                    if (!empty($footnote_element)) {
78                        ksort($footnote_element);
79                        foreach ($footnote_element as $links) {
80                            $newelements[] = $links;
81                        }
82                        $footnote_element = [];
83                    }
84                    if (!empty($lastelement)) {
85                        $newelements[] = $lastelement;
86                        $lastelement   = [];
87                    }
88                    $newelements[] = $element;
89                }
90            } else {
91                if (!empty($lastelement)) {
92                    $newelements[] = $lastelement;
93                    $lastelement   = [];
94                }
95                if (!empty($footnote_element)) {
96                    ksort($footnote_element);
97                    foreach ($footnote_element as $links) {
98                        $newelements[] = $links;
99                    }
100                    $footnote_element = [];
101                }
102                $newelements[] = $element;
103            }
104        }
105        if (!empty($lastelement)) {
106            $newelements[] = $lastelement;
107        }
108        if (!empty($footnote_element)) {
109            ksort($footnote_element);
110            foreach ($footnote_element as $links) {
111                $newelements[] = $links;
112            }
113        }
114        $this->elements = $newelements;
115        unset($footnote_element, $lastelement, $newelements);
116
117        $cP = 0; // Class Padding
118
119        // Used with line breaks and cell height calculation within this box only
120        $renderer->largestFontHeight = 0;
121
122        // If current position (left)
123        if ($this->left === ReportBaseElement::CURRENT_POSITION) {
124            $cX = $renderer->getX();
125        } else {
126            $cX = $this->left;
127            $renderer->setX($cX);
128        }
129        // If current position (top)
130        if ($this->top === ReportBaseElement::CURRENT_POSITION) {
131            $this->top = $renderer->getY();
132        } else {
133            $renderer->setY($this->top);
134        }
135
136        // Check the width if set to page wide OR set by xml to larger then page width (margin)
137        if ($this->width == 0 || $this->width > $renderer->getRemainingWidth()) {
138            $this->width = $renderer->getRemainingWidth();
139        }
140        // Setup the CellPadding
141        if ($this->padding) {
142            $cP = $renderer->cPadding;
143        }
144
145        // For padding, we have to use less wrap width
146        $cW = $this->width - ($cP * 2);
147
148        //-- calculate the text box height
149        // Number of lines, will be converted to height
150        $cHT = 0;
151        // Element height (exept text)
152        $eH = 0;
153        // Footnote height (in points)
154        $fH = 0;
155        $w  = 0;
156        //-- $lw is an array
157        // 0 => last line width
158        // 1 => 1 if text was wrapped, 0 if text did not wrap
159        // 2 => number of LF
160        $lw = [];
161        // Element counter
162        $cE = count($this->elements);
163        for ($i = 0; $i < $cE; $i++) {
164            if (is_object($this->elements[$i])) {
165                $ew = $this->elements[$i]->setWrapWidth($cW - $w - 2, $cW);
166                if ($ew == $cW) {
167                    $w = 0;
168                }
169                $lw = $this->elements[$i]->getWidth($renderer);
170                // Text is already gets the # LF
171                $cHT += $lw[2];
172                if ($lw[1] == 1) {
173                    $w = $lw[0];
174                } elseif ($lw[1] == 2) {
175                    $w = 0;
176                } else {
177                    $w += $lw[0];
178                }
179                if ($w > $cW) {
180                    $w = $lw[0];
181                }
182                // For anything else but text (images), get the height
183                $eH += $this->elements[$i]->getHeight($renderer);
184            } else {
185                $fH += abs($renderer->getFootnotesHeight($cW));
186            }
187        }
188
189        // Add up what’s the final height
190        $cH = $this->height;
191        // If any element exist
192        if ($cE > 0) {
193            // Check if this is text or some other element, like images
194            if ($eH == 0) {
195                // Number of LF but at least one line
196                $cHT = ($cHT + 1) * $renderer->cellHeightRatio;
197                // Calculate the cell hight with the largest font size used
198                $cHT *= $renderer->largestFontHeight;
199                if ($cH < $cHT) {
200                    $cH = $cHT;
201                }
202            } else {
203                // This is any other element
204                if ($cH < $eH) {
205                    $cH = $eH;
206                }
207                // Add Footnote height to the rest of the height
208                $cH += $fH;
209            }
210        }
211
212        unset($lw, $cHT, $fH, $w);
213
214        // Finaly, check the last cells height
215        if ($cH < $renderer->lastCellHeight) {
216            $cH = $renderer->lastCellHeight;
217        }
218        // Update max Y incase of a pagebreak
219        // We don't want to over write any images or other stuff
220        $renderer->addMaxY($this->top + $cH);
221
222        // Start to print HTML
223        echo '<div style="position:absolute;top:', $this->top, 'pt;';
224        // LTR (left) or RTL (right)
225        echo $renderer->alignRTL, ':', $cX, 'pt;';
226        // Background color
227        if ($this->fill) {
228            if (!empty($this->bgcolor)) {
229                echo ' background-color:', $this->bgcolor, ';';
230            }
231        }
232        // Print padding only when it’s set
233        if ($this->padding) {
234            // Use Cell around padding to support RTL also
235            echo 'padding:', $cP, 'pt;';
236        }
237        // Border setup
238        if ($this->border) {
239            echo ' border:solid black 1pt;';
240            echo 'width:', ($this->width - 1 - ($cP * 2)), 'pt;height:', $cH - 1, 'pt;';
241        } else {
242            echo 'width:', ($this->width - ($cP * 2)), 'pt;height:', $cH, 'pt;';
243        }
244        echo '">';
245
246        // Do a little "margin" trick before print
247        // to get the correct current position => "."
248        $cXT = $renderer->getX();
249        $cYT = $renderer->getY();
250        $renderer->setXy(0, 0);
251
252        // Print the text elements
253        foreach ($this->elements as $element) {
254            if ($element instanceof ReportBaseElement) {
255                $element->render($renderer, $cX, false);
256            } elseif ($element === 'footnotetexts') {
257                $renderer->footnotes();
258            } elseif ($element === 'addpage') {
259                $renderer->addPage();
260            }
261        }
262        echo "</div>\n";
263
264        // Reset "margins"
265        $renderer->setXy($cXT, $cYT);
266        // This will be mostly used to trick the multiple images last height
267        if ($this->reseth) {
268            $cH = 0;
269        }
270        // New line and some clean up
271        if (!$this->newline) {
272            $renderer->setXy($cX + $this->width, $this->top);
273            $renderer->lastCellHeight = $cH;
274        } else {
275            $renderer->setXy(0, $this->top + $cH + ($cP * 2));
276            $renderer->lastCellHeight = 0;
277        }
278    }
279}
280