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