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