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