1168ff6f3Sric2016<?php 2168ff6f3Sric2016/** 3168ff6f3Sric2016 * webtrees: online genealogy 48fcd0d32SGreg Roach * Copyright (C) 2019 webtrees development team 5168ff6f3Sric2016 * This program is free software: you can redistribute it and/or modify 6168ff6f3Sric2016 * it under the terms of the GNU General Public License as published by 7168ff6f3Sric2016 * the Free Software Foundation, either version 3 of the License, or 8168ff6f3Sric2016 * (at your option) any later version. 9168ff6f3Sric2016 * This program is distributed in the hope that it will be useful, 10168ff6f3Sric2016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11168ff6f3Sric2016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12168ff6f3Sric2016 * GNU General Public License for more details. 13168ff6f3Sric2016 * You should have received a copy of the GNU General Public License 14168ff6f3Sric2016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15168ff6f3Sric2016 */ 16e7f56f2aSGreg Roachdeclare(strict_types=1); 17e7f56f2aSGreg Roach 18168ff6f3Sric2016namespace Fisharebest\Webtrees\Module; 19168ff6f3Sric2016 20389266c0SGreg Roachuse Fisharebest\Webtrees\Auth; 21e5a6b4d4SGreg Roachuse Fisharebest\Webtrees\Contracts\UserInterface; 22389266c0SGreg Roachuse Fisharebest\Webtrees\Functions\FunctionsPrint; 23168ff6f3Sric2016use Fisharebest\Webtrees\I18N; 24168ff6f3Sric2016use Fisharebest\Webtrees\Individual; 25e46b0479SScrutinizer Auto-Fixeruse Fisharebest\Webtrees\Menu; 26389266c0SGreg Roachuse Fisharebest\Webtrees\Tree; 27389266c0SGreg Roachuse stdClass; 28389266c0SGreg Roachuse Symfony\Component\HttpFoundation\Request; 29389266c0SGreg Roachuse Symfony\Component\HttpFoundation\Response; 30168ff6f3Sric2016 31168ff6f3Sric2016/** 32168ff6f3Sric2016 * Class FamilyBookChartModule 33168ff6f3Sric2016 */ 3437eb8894SGreg Roachclass FamilyBookChartModule extends AbstractModule implements ModuleChartInterface 35c1010edaSGreg Roach{ 3649a243cbSGreg Roach use ModuleChartTrait; 3749a243cbSGreg Roach 38389266c0SGreg Roach // Defaults 39389266c0SGreg Roach private const DEFAULT_GENERATIONS = '2'; 40389266c0SGreg Roach private const DEFAULT_DESCENDANT_GENERATIONS = '5'; 41389266c0SGreg Roach private const DEFAULT_MAXIMUM_GENERATIONS = '9'; 42389266c0SGreg Roach 43389266c0SGreg Roach /** @var stdClass */ 44389266c0SGreg Roach private $box; 45389266c0SGreg Roach 46389266c0SGreg Roach /** @var bool */ 47389266c0SGreg Roach private $show_spouse; 48389266c0SGreg Roach 49389266c0SGreg Roach /** @var int */ 50389266c0SGreg Roach private $descent; 51389266c0SGreg Roach 52389266c0SGreg Roach /** @var int */ 53389266c0SGreg Roach private $bhalfheight; 54389266c0SGreg Roach 55389266c0SGreg Roach /** @var int */ 56389266c0SGreg Roach private $generations; 57389266c0SGreg Roach 58389266c0SGreg Roach /** @var int */ 59389266c0SGreg Roach private $dgenerations; 60389266c0SGreg Roach 61168ff6f3Sric2016 /** 62168ff6f3Sric2016 * How should this module be labelled on tabs, menus, etc.? 63168ff6f3Sric2016 * 64168ff6f3Sric2016 * @return string 65168ff6f3Sric2016 */ 6649a243cbSGreg Roach public function title(): string 67c1010edaSGreg Roach { 68bbb76c12SGreg Roach /* I18N: Name of a module/chart */ 69bbb76c12SGreg Roach return I18N::translate('Family book'); 70168ff6f3Sric2016 } 71168ff6f3Sric2016 72168ff6f3Sric2016 /** 73168ff6f3Sric2016 * A sentence describing what this module does. 74168ff6f3Sric2016 * 75168ff6f3Sric2016 * @return string 76168ff6f3Sric2016 */ 7749a243cbSGreg Roach public function description(): string 78c1010edaSGreg Roach { 79bbb76c12SGreg Roach /* I18N: Description of the “FamilyBookChart” module */ 80bbb76c12SGreg Roach return I18N::translate('A chart of an individual’s ancestors and descendants, as a family book.'); 81168ff6f3Sric2016 } 82168ff6f3Sric2016 83168ff6f3Sric2016 /** 84377a2979SGreg Roach * CSS class for the URL. 85377a2979SGreg Roach * 86377a2979SGreg Roach * @return string 87377a2979SGreg Roach */ 88377a2979SGreg Roach public function chartMenuClass(): string 89377a2979SGreg Roach { 90377a2979SGreg Roach return 'menu-chart-familybook'; 91377a2979SGreg Roach } 92377a2979SGreg Roach 93377a2979SGreg Roach /** 944eb71cfaSGreg Roach * Return a menu item for this chart - for use in individual boxes. 954eb71cfaSGreg Roach * 9660bc3e3fSGreg Roach * @param Individual $individual 9760bc3e3fSGreg Roach * 984eb71cfaSGreg Roach * @return Menu|null 994eb71cfaSGreg Roach */ 100377a2979SGreg Roach public function chartBoxMenu(Individual $individual): ?Menu 101c1010edaSGreg Roach { 102e6562982SGreg Roach return $this->chartMenu($individual); 103e6562982SGreg Roach } 104e6562982SGreg Roach 105e6562982SGreg Roach /** 106e6562982SGreg Roach * The title for a specific instance of this chart. 107e6562982SGreg Roach * 108e6562982SGreg Roach * @param Individual $individual 109e6562982SGreg Roach * 110e6562982SGreg Roach * @return string 111e6562982SGreg Roach */ 112e6562982SGreg Roach public function chartTitle(Individual $individual): string 113e6562982SGreg Roach { 114e6562982SGreg Roach /* I18N: %s is an individual’s name */ 115e6562982SGreg Roach return I18N::translate('Family book of %s', $individual->getFullName()); 116e6562982SGreg Roach } 117e6562982SGreg Roach 118e6562982SGreg Roach /** 119389266c0SGreg Roach * A form to request the chart parameters. 120389266c0SGreg Roach * 121389266c0SGreg Roach * @param Request $request 122389266c0SGreg Roach * @param Tree $tree 123e5a6b4d4SGreg Roach * @param UserInterface $user 124389266c0SGreg Roach * 125389266c0SGreg Roach * @return Response 126389266c0SGreg Roach */ 127e5a6b4d4SGreg Roach public function getChartAction(Request $request, Tree $tree, UserInterface $user): Response 128389266c0SGreg Roach { 1299b5537c3SGreg Roach $ajax = (bool) $request->get('ajax'); 130389266c0SGreg Roach $xref = $request->get('xref', ''); 131389266c0SGreg Roach $individual = Individual::getInstance($xref, $tree); 132389266c0SGreg Roach 133389266c0SGreg Roach Auth::checkIndividualAccess($individual); 1349867b2f0SGreg Roach Auth::checkComponentAccess($this, 'chart', $tree, $user); 135389266c0SGreg Roach 136389266c0SGreg Roach $minimum_generations = 2; 137389266c0SGreg Roach $maximum_generations = (int) $tree->getPreference('MAX_DESCENDANCY_GENERATIONS', self::DEFAULT_MAXIMUM_GENERATIONS); 138389266c0SGreg Roach $default_generations = (int) $tree->getPreference('DEFAULT_PEDIGREE_GENERATIONS', self::DEFAULT_GENERATIONS); 139389266c0SGreg Roach 140389266c0SGreg Roach $show_spouse = (bool) $request->get('show_spouse'); 141389266c0SGreg Roach $generations = (int) $request->get('generations', $default_generations); 142389266c0SGreg Roach $generations = min($generations, $maximum_generations); 143389266c0SGreg Roach $generations = max($generations, $minimum_generations); 144389266c0SGreg Roach 145389266c0SGreg Roach // Generations of ancestors/descendants in each mini-tree. 146389266c0SGreg Roach $book_size = (int) $request->get('book_size', 2); 147389266c0SGreg Roach $book_size = min($book_size, 5); 148389266c0SGreg Roach $book_size = max($book_size, 2); 149389266c0SGreg Roach 1509b5537c3SGreg Roach if ($ajax) { 151389266c0SGreg Roach return $this->chart($individual, $generations, $book_size, $show_spouse); 152389266c0SGreg Roach } 153389266c0SGreg Roach 154389266c0SGreg Roach $ajax_url = $this->chartUrl($individual, [ 1559b5537c3SGreg Roach 'ajax' => true, 156389266c0SGreg Roach 'book_size' => $book_size, 157389266c0SGreg Roach 'generations' => $generations, 158e5a6b4d4SGreg Roach 'show_spouse' => $show_spouse, 159389266c0SGreg Roach ]); 160389266c0SGreg Roach 1619b5537c3SGreg Roach return $this->viewResponse('modules/family-book-chart/page', [ 162389266c0SGreg Roach 'ajax_url' => $ajax_url, 163389266c0SGreg Roach 'book_size' => $book_size, 164389266c0SGreg Roach 'generations' => $generations, 165389266c0SGreg Roach 'individual' => $individual, 166389266c0SGreg Roach 'maximum_generations' => $maximum_generations, 167389266c0SGreg Roach 'minimum_generations' => $minimum_generations, 16826684e68SGreg Roach 'module_name' => $this->name(), 169389266c0SGreg Roach 'show_spouse' => $show_spouse, 170389266c0SGreg Roach 'title' => $this->chartTitle($individual), 171389266c0SGreg Roach ]); 172389266c0SGreg Roach } 173389266c0SGreg Roach 174389266c0SGreg Roach /** 175389266c0SGreg Roach * @param Individual $individual 176389266c0SGreg Roach * @param int $generations 177389266c0SGreg Roach * @param int $book_size 178389266c0SGreg Roach * @param bool $show_spouse 179389266c0SGreg Roach * 180389266c0SGreg Roach * @return Response 181389266c0SGreg Roach */ 182389266c0SGreg Roach public function chart(Individual $individual, int $generations, int $book_size, bool $show_spouse): Response 183389266c0SGreg Roach { 184389266c0SGreg Roach $this->box = (object) [ 1858136679eSGreg Roach 'width' => app()->make(ModuleThemeInterface::class)->parameter('chart-box-x'), 1868136679eSGreg Roach 'height' => app()->make(ModuleThemeInterface::class)->parameter('chart-box-y'), 187389266c0SGreg Roach ]; 188389266c0SGreg Roach 189389266c0SGreg Roach $this->show_spouse = $show_spouse; 190389266c0SGreg Roach $this->descent = $generations; 191389266c0SGreg Roach $this->generations = $book_size; 192389266c0SGreg Roach 193389266c0SGreg Roach $this->bhalfheight = $this->box->height / 2; 194389266c0SGreg Roach $this->dgenerations = $this->maxDescendencyGenerations($individual, 0); 195389266c0SGreg Roach 196389266c0SGreg Roach if ($this->dgenerations < 1) { 197389266c0SGreg Roach $this->dgenerations = 1; 198389266c0SGreg Roach } 199389266c0SGreg Roach 200389266c0SGreg Roach // @TODO - this is just a wrapper around the old code. 201389266c0SGreg Roach ob_start(); 202389266c0SGreg Roach $this->printFamilyBook($individual, $generations); 203389266c0SGreg Roach $html = ob_get_clean(); 204389266c0SGreg Roach 205389266c0SGreg Roach return new Response($html); 206389266c0SGreg Roach } 207389266c0SGreg Roach 208389266c0SGreg Roach /** 209389266c0SGreg Roach * Prints descendency of passed in person 210389266c0SGreg Roach * 211389266c0SGreg Roach * @param int $generation 212389266c0SGreg Roach * @param Individual|null $person 213389266c0SGreg Roach * 214389266c0SGreg Roach * @return float 215389266c0SGreg Roach */ 216389266c0SGreg Roach private function printDescendency($generation, Individual $person = null): float 217389266c0SGreg Roach { 218389266c0SGreg Roach if ($generation > $this->dgenerations) { 219389266c0SGreg Roach return 0; 220389266c0SGreg Roach } 221389266c0SGreg Roach 222389266c0SGreg Roach echo '<table cellspacing="0" cellpadding="0" border="0" ><tr><td>'; 223389266c0SGreg Roach $numkids = 0.0; 224389266c0SGreg Roach 225389266c0SGreg Roach // Load children 226389266c0SGreg Roach $children = []; 227389266c0SGreg Roach if ($person instanceof Individual) { 228389266c0SGreg Roach // Count is position from center to left, dgenerations is number of generations 229389266c0SGreg Roach if ($generation < $this->dgenerations) { 230389266c0SGreg Roach // All children, from all partners 231389266c0SGreg Roach foreach ($person->getSpouseFamilies() as $family) { 232389266c0SGreg Roach foreach ($family->getChildren() as $child) { 233389266c0SGreg Roach $children[] = $child; 234389266c0SGreg Roach } 235389266c0SGreg Roach } 236389266c0SGreg Roach } 237389266c0SGreg Roach } 238389266c0SGreg Roach if ($generation < $this->dgenerations) { 239389266c0SGreg Roach if (!empty($children)) { 240389266c0SGreg Roach // real people 241389266c0SGreg Roach echo '<table cellspacing="0" cellpadding="0" border="0" >'; 242389266c0SGreg Roach foreach ($children as $i => $child) { 243389266c0SGreg Roach echo '<tr><td>'; 244389266c0SGreg Roach $kids = $this->printDescendency($generation + 1, $child); 245389266c0SGreg Roach $numkids += $kids; 246389266c0SGreg Roach echo '</td>'; 247389266c0SGreg Roach // Print the lines 248389266c0SGreg Roach if (count($children) > 1) { 249389266c0SGreg Roach if ($i === 0) { 250389266c0SGreg Roach // Adjust for the first column on left 251389266c0SGreg Roach $h = round(((($this->box->height) * $kids) + 8) / 2); // Assumes border = 1 and padding = 3 252389266c0SGreg Roach // Adjust for other vertical columns 253389266c0SGreg Roach if ($kids > 1) { 254389266c0SGreg Roach $h = ($kids - 1) * 4 + $h; 255389266c0SGreg Roach } 256389266c0SGreg Roach echo '<td class="align-bottom">', 257e837ff07SGreg Roach '<img id="vline_', $child->xref(), '" src="', e(asset('css/images/vline.png')), '" width="3" height="', $h - 4, '"></td>'; 258389266c0SGreg Roach } elseif ($i === count($children) - 1) { 259389266c0SGreg Roach // Adjust for the first column on left 260389266c0SGreg Roach $h = round(((($this->box->height) * $kids) + 8) / 2); 261389266c0SGreg Roach // Adjust for other vertical columns 262389266c0SGreg Roach if ($kids > 1) { 263389266c0SGreg Roach $h = ($kids - 1) * 4 + $h; 264389266c0SGreg Roach } 265389266c0SGreg Roach echo '<td class="align-top">', 266e837ff07SGreg Roach '<img class="bvertline" width="3" id="vline_', $child->xref(), '" src="', e(asset('css/images/vline.png')), '" height="', $h - 2, '"></td>'; 267389266c0SGreg Roach } else { 268e837ff07SGreg Roach echo '<td class="align-bottomm"style="background: url(', e(asset('css/images/vline.png')), ');">', 269e837ff07SGreg Roach '<img class="spacer" width="3" src="', e(asset('css/images/spacer.png')), '"></td>'; 270389266c0SGreg Roach } 271389266c0SGreg Roach } 272389266c0SGreg Roach echo '</tr>'; 273389266c0SGreg Roach } 274389266c0SGreg Roach echo '</table>'; 275389266c0SGreg Roach } else { 276389266c0SGreg Roach // Hidden/empty boxes - to preserve the layout 277389266c0SGreg Roach echo '<table cellspacing="0" cellpadding="0" border="0" ><tr><td>'; 278389266c0SGreg Roach $numkids += $this->printDescendency($generation + 1, null); 279389266c0SGreg Roach echo '</td></tr></table>'; 280389266c0SGreg Roach } 281389266c0SGreg Roach echo '</td>'; 282389266c0SGreg Roach echo '<td>'; 283389266c0SGreg Roach } 284389266c0SGreg Roach 285389266c0SGreg Roach if ($numkids === 0.0) { 286389266c0SGreg Roach $numkids = 1; 287389266c0SGreg Roach } 288389266c0SGreg Roach echo '<table cellspacing="0" cellpadding="0" border="0" ><tr><td>'; 289389266c0SGreg Roach if ($person instanceof Individual) { 290389266c0SGreg Roach echo FunctionsPrint::printPedigreePerson($person); 291389266c0SGreg Roach echo '</td><td>', 292e837ff07SGreg Roach '<img class="linef1" src="', e(asset('css/images/hline.png')), '" width="8" height="3">'; 293389266c0SGreg Roach } else { 294389266c0SGreg Roach echo '<div style="width:', $this->box->width + 19, 'px; height:', $this->box->height + 8, 'px;"></div>', 295389266c0SGreg Roach '</td><td>'; 296389266c0SGreg Roach } 297389266c0SGreg Roach 298389266c0SGreg Roach // Print the spouse 299389266c0SGreg Roach if ($generation === 1 && $person instanceof Individual) { 300389266c0SGreg Roach if ($this->show_spouse) { 301389266c0SGreg Roach foreach ($person->getSpouseFamilies() as $family) { 302389266c0SGreg Roach $spouse = $family->getSpouse($person); 303389266c0SGreg Roach echo '</td></tr><tr><td>'; 304389266c0SGreg Roach echo FunctionsPrint::printPedigreePerson($spouse); 305389266c0SGreg Roach $numkids += 0.95; 306389266c0SGreg Roach echo '</td><td>'; 307389266c0SGreg Roach } 308389266c0SGreg Roach } 309389266c0SGreg Roach } 310389266c0SGreg Roach echo '</td></tr></table>'; 311389266c0SGreg Roach echo '</td></tr>'; 312389266c0SGreg Roach echo '</table>'; 313389266c0SGreg Roach 314389266c0SGreg Roach return $numkids; 315389266c0SGreg Roach } 316389266c0SGreg Roach 317389266c0SGreg Roach /** 318389266c0SGreg Roach * Prints pedigree of the person passed in 319389266c0SGreg Roach * 320389266c0SGreg Roach * @param Individual $person 321389266c0SGreg Roach * @param int $count 322389266c0SGreg Roach * 323389266c0SGreg Roach * @return void 324389266c0SGreg Roach */ 325389266c0SGreg Roach private function printPersonPedigree($person, $count) 326389266c0SGreg Roach { 327389266c0SGreg Roach if ($count >= $this->generations) { 328389266c0SGreg Roach return; 329389266c0SGreg Roach } 330389266c0SGreg Roach 331389266c0SGreg Roach $genoffset = $this->generations; // handle pedigree n generations lines 332389266c0SGreg Roach //-- calculate how tall the lines should be 333389266c0SGreg Roach $lh = ($this->bhalfheight) * (2 ** ($genoffset - $count - 1)); 334389266c0SGreg Roach // 335389266c0SGreg Roach //Prints empty table columns for children w/o parents up to the max generation 336389266c0SGreg Roach //This allows vertical line spacing to be consistent 337389266c0SGreg Roach if (count($person->getChildFamilies()) == 0) { 338389266c0SGreg Roach echo '<table cellspacing="0" cellpadding="0" border="0" >'; 339389266c0SGreg Roach $this->printEmptyBox(); 340389266c0SGreg Roach 341389266c0SGreg Roach //-- recursively get the father’s family 342389266c0SGreg Roach $this->printPersonPedigree($person, $count + 1); 343389266c0SGreg Roach echo '</td><td></tr>'; 344389266c0SGreg Roach $this->printEmptyBox(); 345389266c0SGreg Roach 346389266c0SGreg Roach //-- recursively get the mother’s family 347389266c0SGreg Roach $this->printPersonPedigree($person, $count + 1); 348389266c0SGreg Roach echo '</td><td></tr></table>'; 349389266c0SGreg Roach } 350389266c0SGreg Roach 351389266c0SGreg Roach // Empty box section done, now for regular pedigree 352389266c0SGreg Roach foreach ($person->getChildFamilies() as $family) { 353389266c0SGreg Roach echo '<table cellspacing="0" cellpadding="0" border="0" ><tr><td class="align-bottom">'; 354389266c0SGreg Roach // Determine line height for two or more spouces 355389266c0SGreg Roach // And then adjust the vertical line for the root person only 356389266c0SGreg Roach $famcount = 0; 357389266c0SGreg Roach if ($this->show_spouse) { 358389266c0SGreg Roach // count number of spouses 359389266c0SGreg Roach $famcount += count($person->getSpouseFamilies()); 360389266c0SGreg Roach } 361389266c0SGreg Roach $savlh = $lh; // Save current line height 362389266c0SGreg Roach if ($count == 1 && $genoffset <= $famcount) { 363389266c0SGreg Roach $linefactor = 0; 364389266c0SGreg Roach // genoffset of 2 needs no adjustment 365389266c0SGreg Roach if ($genoffset > 2) { 366389266c0SGreg Roach $tblheight = $this->box->height + 8; 367389266c0SGreg Roach if ($genoffset == 3) { 368389266c0SGreg Roach if ($famcount == 3) { 369389266c0SGreg Roach $linefactor = $tblheight / 2; 370389266c0SGreg Roach } elseif ($famcount > 3) { 371389266c0SGreg Roach $linefactor = $tblheight; 372389266c0SGreg Roach } 373389266c0SGreg Roach } 374389266c0SGreg Roach if ($genoffset == 4) { 375389266c0SGreg Roach if ($famcount == 4) { 376389266c0SGreg Roach $linefactor = $tblheight; 377389266c0SGreg Roach } elseif ($famcount > 4) { 378389266c0SGreg Roach $linefactor = ($famcount - $genoffset) * ($tblheight * 1.5); 379389266c0SGreg Roach } 380389266c0SGreg Roach } 381389266c0SGreg Roach if ($genoffset == 5) { 382389266c0SGreg Roach if ($famcount == 5) { 383389266c0SGreg Roach $linefactor = 0; 384389266c0SGreg Roach } elseif ($famcount > 5) { 385389266c0SGreg Roach $linefactor = $tblheight * ($famcount - $genoffset); 386389266c0SGreg Roach } 387389266c0SGreg Roach } 388389266c0SGreg Roach } 389389266c0SGreg Roach $lh = (($famcount - 1) * ($this->box->height) - ($linefactor)); 390389266c0SGreg Roach if ($genoffset > 5) { 391389266c0SGreg Roach $lh = $savlh; 392389266c0SGreg Roach } 393389266c0SGreg Roach } 394e837ff07SGreg Roach echo '<img class="line3 pvline" src="', e(asset('css/images/vline.png')), '" width="3" height="', $lh, '"></td>', 395389266c0SGreg Roach '<td>', 396e837ff07SGreg Roach '<img class="linef2" src="', e(asset('css/images/hline.png')), '" height="3"></td>', 397389266c0SGreg Roach '<td>'; 398389266c0SGreg Roach $lh = $savlh; // restore original line height 399389266c0SGreg Roach //-- print the father box 400389266c0SGreg Roach echo FunctionsPrint::printPedigreePerson($family->getHusband()); 401389266c0SGreg Roach echo '</td>'; 402389266c0SGreg Roach if ($family->getHusband()) { 403389266c0SGreg Roach echo '<td>'; 404389266c0SGreg Roach //-- recursively get the father’s family 405389266c0SGreg Roach $this->printPersonPedigree($family->getHusband(), $count + 1); 406389266c0SGreg Roach echo '</td>'; 407389266c0SGreg Roach } else { 408389266c0SGreg Roach echo '<td>'; 409389266c0SGreg Roach if ($genoffset > $count) { 410389266c0SGreg Roach echo '<table cellspacing="0" cellpadding="0" border="0" >'; 411389266c0SGreg Roach for ($i = 1; $i < (pow(2, ($genoffset) - $count) / 2); $i++) { 412389266c0SGreg Roach $this->printEmptyBox(); 413389266c0SGreg Roach echo '</tr>'; 414389266c0SGreg Roach } 415389266c0SGreg Roach echo '</table>'; 416389266c0SGreg Roach } 417389266c0SGreg Roach } 418389266c0SGreg Roach echo '</tr><tr>', 419e837ff07SGreg Roach '<td class="align-top"><img class="pvline" alt="" role="presentation" src="', e(asset('css/images/vline.png')), '" width="3" height="', $lh, '"></td>', 420e837ff07SGreg Roach '<td><img class="linef3" alt="" role="presentation" src="', e(asset('css/images/hline.png')), '" height="3"></td>', 421389266c0SGreg Roach '<td>'; 422389266c0SGreg Roach //-- print the mother box 423389266c0SGreg Roach echo FunctionsPrint::printPedigreePerson($family->getWife()); 424389266c0SGreg Roach echo '</td>'; 425389266c0SGreg Roach if ($family->getWife()) { 426389266c0SGreg Roach echo '<td>'; 427389266c0SGreg Roach //-- recursively print the mother’s family 428389266c0SGreg Roach $this->printPersonPedigree($family->getWife(), $count + 1); 429389266c0SGreg Roach echo '</td>'; 430389266c0SGreg Roach } else { 431389266c0SGreg Roach echo '<td>'; 432389266c0SGreg Roach if ($count < $genoffset - 1) { 433389266c0SGreg Roach echo '<table cellspacing="0" cellpadding="0" border="0" >'; 434389266c0SGreg Roach for ($i = 1; $i < (pow(2, ($genoffset - 1) - $count) / 2) + 1; $i++) { 435389266c0SGreg Roach $this->printEmptyBox(); 436389266c0SGreg Roach echo '</tr>'; 437389266c0SGreg Roach $this->printEmptyBox(); 438389266c0SGreg Roach echo '</tr>'; 439389266c0SGreg Roach } 440389266c0SGreg Roach echo '</table>'; 441389266c0SGreg Roach } 442389266c0SGreg Roach } 443389266c0SGreg Roach echo '</tr>', 444389266c0SGreg Roach '</table>'; 445389266c0SGreg Roach break; 446389266c0SGreg Roach } 447389266c0SGreg Roach } 448389266c0SGreg Roach 449389266c0SGreg Roach /** 450389266c0SGreg Roach * Calculates number of generations a person has 451e6562982SGreg Roach * 452e6562982SGreg Roach * @param Individual $individual 453389266c0SGreg Roach * @param int $depth 454e6562982SGreg Roach * 455389266c0SGreg Roach * @return int 456e6562982SGreg Roach */ 457389266c0SGreg Roach private function maxDescendencyGenerations(Individual $individual, $depth): int 458e6562982SGreg Roach { 459389266c0SGreg Roach if ($depth > $this->generations) { 460389266c0SGreg Roach return $depth; 461389266c0SGreg Roach } 462389266c0SGreg Roach $maxdc = $depth; 463389266c0SGreg Roach foreach ($individual->getSpouseFamilies() as $family) { 464389266c0SGreg Roach foreach ($family->getChildren() as $child) { 465389266c0SGreg Roach $dc = $this->maxDescendencyGenerations($child, $depth + 1); 466389266c0SGreg Roach if ($dc >= $this->generations) { 467389266c0SGreg Roach return $dc; 468389266c0SGreg Roach } 469389266c0SGreg Roach if ($dc > $maxdc) { 470389266c0SGreg Roach $maxdc = $dc; 471389266c0SGreg Roach } 472389266c0SGreg Roach } 473389266c0SGreg Roach } 474389266c0SGreg Roach $maxdc++; 475389266c0SGreg Roach if ($maxdc == 1) { 476389266c0SGreg Roach $maxdc++; 477389266c0SGreg Roach } 478389266c0SGreg Roach 479389266c0SGreg Roach return $maxdc; 480389266c0SGreg Roach } 481389266c0SGreg Roach 482389266c0SGreg Roach /** 483389266c0SGreg Roach * Print empty box 484389266c0SGreg Roach * 485389266c0SGreg Roach * @return void 486389266c0SGreg Roach */ 487389266c0SGreg Roach 488389266c0SGreg Roach private function printEmptyBox() 489389266c0SGreg Roach { 4908136679eSGreg Roach echo app()->make(ModuleThemeInterface::class)->individualBoxEmpty(); 491389266c0SGreg Roach } 492389266c0SGreg Roach 493389266c0SGreg Roach /** 494389266c0SGreg Roach * Print a “Family Book” for an individual 495389266c0SGreg Roach * 496389266c0SGreg Roach * @param Individual $person 497389266c0SGreg Roach * @param int $descent_steps 498389266c0SGreg Roach * 499389266c0SGreg Roach * @return void 500389266c0SGreg Roach */ 501389266c0SGreg Roach private function printFamilyBook(Individual $person, $descent_steps) 502389266c0SGreg Roach { 503389266c0SGreg Roach if ($descent_steps == 0) { 504389266c0SGreg Roach return; 505389266c0SGreg Roach } 506389266c0SGreg Roach 507389266c0SGreg Roach echo 508389266c0SGreg Roach '<h3>', 509389266c0SGreg Roach /* I18N: %s is an individual’s name */ 510389266c0SGreg Roach I18N::translate('Family of %s', $person->getFullName()), 511389266c0SGreg Roach '</h3>', 512389266c0SGreg Roach '<table cellspacing="0" cellpadding="0" border="0" ><tr><td class="align-middle">'; 513389266c0SGreg Roach $this->dgenerations = $this->generations; 514389266c0SGreg Roach $this->printDescendency(1, $person); 515389266c0SGreg Roach echo '</td><td class="align-middle">'; 516389266c0SGreg Roach $this->printPersonPedigree($person, 1); 517*242a7862SGreg Roach echo '</td></tr></table><br><br><hr class="wt-family-break"><br><br>'; 518389266c0SGreg Roach foreach ($person->getSpouseFamilies() as $family) { 519389266c0SGreg Roach foreach ($family->getChildren() as $child) { 520389266c0SGreg Roach $this->printFamilyBook($child, $descent_steps - 1); 521389266c0SGreg Roach } 522389266c0SGreg Roach } 523e6562982SGreg Roach } 524168ff6f3Sric2016} 525