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; 21389266c0SGreg Roachuse Fisharebest\Webtrees\Functions\FunctionsPrint; 22168ff6f3Sric2016use Fisharebest\Webtrees\I18N; 23168ff6f3Sric2016use Fisharebest\Webtrees\Individual; 24e46b0479SScrutinizer Auto-Fixeruse Fisharebest\Webtrees\Menu; 25389266c0SGreg Roachuse Fisharebest\Webtrees\Theme; 26389266c0SGreg Roachuse Fisharebest\Webtrees\Tree; 27*9867b2f0SGreg Roachuse Fisharebest\Webtrees\User; 28389266c0SGreg Roachuse stdClass; 29389266c0SGreg Roachuse Symfony\Component\HttpFoundation\Request; 30389266c0SGreg Roachuse Symfony\Component\HttpFoundation\Response; 31168ff6f3Sric2016 32168ff6f3Sric2016/** 33168ff6f3Sric2016 * Class FamilyBookChartModule 34168ff6f3Sric2016 */ 3537eb8894SGreg Roachclass FamilyBookChartModule extends AbstractModule implements ModuleChartInterface 36c1010edaSGreg Roach{ 3749a243cbSGreg Roach use ModuleChartTrait; 3849a243cbSGreg Roach 39389266c0SGreg Roach // Defaults 40389266c0SGreg Roach private const DEFAULT_GENERATIONS = '2'; 41389266c0SGreg Roach private const DEFAULT_DESCENDANT_GENERATIONS = '5'; 42389266c0SGreg Roach private const DEFAULT_MAXIMUM_GENERATIONS = '9'; 43389266c0SGreg Roach 44389266c0SGreg Roach /** @var stdClass */ 45389266c0SGreg Roach private $box; 46389266c0SGreg Roach 47389266c0SGreg Roach /** @var bool */ 48389266c0SGreg Roach private $show_spouse; 49389266c0SGreg Roach 50389266c0SGreg Roach /** @var int */ 51389266c0SGreg Roach private $descent; 52389266c0SGreg Roach 53389266c0SGreg Roach /** @var int */ 54389266c0SGreg Roach private $bhalfheight; 55389266c0SGreg Roach 56389266c0SGreg Roach /** @var int */ 57389266c0SGreg Roach private $generations; 58389266c0SGreg Roach 59389266c0SGreg Roach /** @var int */ 60389266c0SGreg Roach private $dgenerations; 61389266c0SGreg Roach 62168ff6f3Sric2016 /** 63168ff6f3Sric2016 * How should this module be labelled on tabs, menus, etc.? 64168ff6f3Sric2016 * 65168ff6f3Sric2016 * @return string 66168ff6f3Sric2016 */ 6749a243cbSGreg Roach public function title(): string 68c1010edaSGreg Roach { 69bbb76c12SGreg Roach /* I18N: Name of a module/chart */ 70bbb76c12SGreg Roach return I18N::translate('Family book'); 71168ff6f3Sric2016 } 72168ff6f3Sric2016 73168ff6f3Sric2016 /** 74168ff6f3Sric2016 * A sentence describing what this module does. 75168ff6f3Sric2016 * 76168ff6f3Sric2016 * @return string 77168ff6f3Sric2016 */ 7849a243cbSGreg Roach public function description(): string 79c1010edaSGreg Roach { 80bbb76c12SGreg Roach /* I18N: Description of the “FamilyBookChart” module */ 81bbb76c12SGreg Roach return I18N::translate('A chart of an individual’s ancestors and descendants, as a family book.'); 82168ff6f3Sric2016 } 83168ff6f3Sric2016 84168ff6f3Sric2016 /** 85377a2979SGreg Roach * CSS class for the URL. 86377a2979SGreg Roach * 87377a2979SGreg Roach * @return string 88377a2979SGreg Roach */ 89377a2979SGreg Roach public function chartMenuClass(): string 90377a2979SGreg Roach { 91377a2979SGreg Roach return 'menu-chart-familybook'; 92377a2979SGreg Roach } 93377a2979SGreg Roach 94377a2979SGreg Roach /** 954eb71cfaSGreg Roach * Return a menu item for this chart - for use in individual boxes. 964eb71cfaSGreg Roach * 9760bc3e3fSGreg Roach * @param Individual $individual 9860bc3e3fSGreg Roach * 994eb71cfaSGreg Roach * @return Menu|null 1004eb71cfaSGreg Roach */ 101377a2979SGreg Roach public function chartBoxMenu(Individual $individual): ?Menu 102c1010edaSGreg Roach { 103e6562982SGreg Roach return $this->chartMenu($individual); 104e6562982SGreg Roach } 105e6562982SGreg Roach 106e6562982SGreg Roach /** 107e6562982SGreg Roach * The title for a specific instance of this chart. 108e6562982SGreg Roach * 109e6562982SGreg Roach * @param Individual $individual 110e6562982SGreg Roach * 111e6562982SGreg Roach * @return string 112e6562982SGreg Roach */ 113e6562982SGreg Roach public function chartTitle(Individual $individual): string 114e6562982SGreg Roach { 115e6562982SGreg Roach /* I18N: %s is an individual’s name */ 116e6562982SGreg Roach return I18N::translate('Family book of %s', $individual->getFullName()); 117e6562982SGreg Roach } 118e6562982SGreg Roach 119e6562982SGreg Roach /** 120389266c0SGreg Roach * A form to request the chart parameters. 121389266c0SGreg Roach * 122389266c0SGreg Roach * @param Request $request 123389266c0SGreg Roach * @param Tree $tree 124*9867b2f0SGreg Roach * @param User $user 125389266c0SGreg Roach * 126389266c0SGreg Roach * @return Response 127389266c0SGreg Roach */ 128*9867b2f0SGreg Roach public function getChartAction(Request $request, Tree $tree, User $user): Response 129389266c0SGreg Roach { 1309b5537c3SGreg Roach $ajax = (bool) $request->get('ajax'); 131389266c0SGreg Roach $xref = $request->get('xref', ''); 132389266c0SGreg Roach $individual = Individual::getInstance($xref, $tree); 133389266c0SGreg Roach 134389266c0SGreg Roach Auth::checkIndividualAccess($individual); 135*9867b2f0SGreg Roach Auth::checkComponentAccess($this, 'chart', $tree, $user); 136389266c0SGreg Roach 137389266c0SGreg Roach $minimum_generations = 2; 138389266c0SGreg Roach $maximum_generations = (int) $tree->getPreference('MAX_DESCENDANCY_GENERATIONS', self::DEFAULT_MAXIMUM_GENERATIONS); 139389266c0SGreg Roach $default_generations = (int) $tree->getPreference('DEFAULT_PEDIGREE_GENERATIONS', self::DEFAULT_GENERATIONS); 140389266c0SGreg Roach 141389266c0SGreg Roach $show_spouse = (bool) $request->get('show_spouse'); 142389266c0SGreg Roach $generations = (int) $request->get('generations', $default_generations); 143389266c0SGreg Roach $generations = min($generations, $maximum_generations); 144389266c0SGreg Roach $generations = max($generations, $minimum_generations); 145389266c0SGreg Roach 146389266c0SGreg Roach // Generations of ancestors/descendants in each mini-tree. 147389266c0SGreg Roach $book_size = (int) $request->get('book_size', 2); 148389266c0SGreg Roach $book_size = min($book_size, 5); 149389266c0SGreg Roach $book_size = max($book_size, 2); 150389266c0SGreg Roach 1519b5537c3SGreg Roach if ($ajax) { 152389266c0SGreg Roach return $this->chart($individual, $generations, $book_size, $show_spouse); 153389266c0SGreg Roach } 154389266c0SGreg Roach 155389266c0SGreg Roach $ajax_url = $this->chartUrl($individual, [ 1569b5537c3SGreg Roach 'ajax' => true, 157389266c0SGreg Roach 'book_size' => $book_size, 158389266c0SGreg Roach 'generations' => $generations, 159389266c0SGreg Roach 'show_spouse' => $show_spouse 160389266c0SGreg Roach ]); 161389266c0SGreg Roach 1629b5537c3SGreg Roach return $this->viewResponse('modules/family-book-chart/page', [ 163389266c0SGreg Roach 'ajax_url' => $ajax_url, 164389266c0SGreg Roach 'book_size' => $book_size, 165389266c0SGreg Roach 'generations' => $generations, 166389266c0SGreg Roach 'individual' => $individual, 167389266c0SGreg Roach 'maximum_generations' => $maximum_generations, 168389266c0SGreg Roach 'minimum_generations' => $minimum_generations, 16926684e68SGreg Roach 'module_name' => $this->name(), 170389266c0SGreg Roach 'show_spouse' => $show_spouse, 171389266c0SGreg Roach 'title' => $this->chartTitle($individual), 172389266c0SGreg Roach ]); 173389266c0SGreg Roach } 174389266c0SGreg Roach 175389266c0SGreg Roach /** 176389266c0SGreg Roach * @param Individual $individual 177389266c0SGreg Roach * @param int $generations 178389266c0SGreg Roach * @param int $book_size 179389266c0SGreg Roach * @param bool $show_spouse 180389266c0SGreg Roach * 181389266c0SGreg Roach * @return Response 182389266c0SGreg Roach */ 183389266c0SGreg Roach public function chart(Individual $individual, int $generations, int $book_size, bool $show_spouse): Response 184389266c0SGreg Roach { 185389266c0SGreg Roach $this->box = (object) [ 186389266c0SGreg Roach 'width' => Theme::theme()->parameter('chart-box-x'), 187389266c0SGreg Roach 'height' => Theme::theme()->parameter('chart-box-y'), 188389266c0SGreg Roach ]; 189389266c0SGreg Roach 190389266c0SGreg Roach $this->show_spouse = $show_spouse; 191389266c0SGreg Roach $this->descent = $generations; 192389266c0SGreg Roach $this->generations = $book_size; 193389266c0SGreg Roach 194389266c0SGreg Roach $this->bhalfheight = $this->box->height / 2; 195389266c0SGreg Roach $this->dgenerations = $this->maxDescendencyGenerations($individual, 0); 196389266c0SGreg Roach 197389266c0SGreg Roach if ($this->dgenerations < 1) { 198389266c0SGreg Roach $this->dgenerations = 1; 199389266c0SGreg Roach } 200389266c0SGreg Roach 201389266c0SGreg Roach // @TODO - this is just a wrapper around the old code. 202389266c0SGreg Roach ob_start(); 203389266c0SGreg Roach $this->printFamilyBook($individual, $generations); 204389266c0SGreg Roach $html = ob_get_clean(); 205389266c0SGreg Roach 206389266c0SGreg Roach return new Response($html); 207389266c0SGreg Roach } 208389266c0SGreg Roach 209389266c0SGreg Roach /** 210389266c0SGreg Roach * Prints descendency of passed in person 211389266c0SGreg Roach * 212389266c0SGreg Roach * @param int $generation 213389266c0SGreg Roach * @param Individual|null $person 214389266c0SGreg Roach * 215389266c0SGreg Roach * @return float 216389266c0SGreg Roach */ 217389266c0SGreg Roach private function printDescendency($generation, Individual $person = null): float 218389266c0SGreg Roach { 219389266c0SGreg Roach if ($generation > $this->dgenerations) { 220389266c0SGreg Roach return 0; 221389266c0SGreg Roach } 222389266c0SGreg Roach 223389266c0SGreg Roach echo '<table cellspacing="0" cellpadding="0" border="0" ><tr><td>'; 224389266c0SGreg Roach $numkids = 0.0; 225389266c0SGreg Roach 226389266c0SGreg Roach // Load children 227389266c0SGreg Roach $children = []; 228389266c0SGreg Roach if ($person instanceof Individual) { 229389266c0SGreg Roach // Count is position from center to left, dgenerations is number of generations 230389266c0SGreg Roach if ($generation < $this->dgenerations) { 231389266c0SGreg Roach // All children, from all partners 232389266c0SGreg Roach foreach ($person->getSpouseFamilies() as $family) { 233389266c0SGreg Roach foreach ($family->getChildren() as $child) { 234389266c0SGreg Roach $children[] = $child; 235389266c0SGreg Roach } 236389266c0SGreg Roach } 237389266c0SGreg Roach } 238389266c0SGreg Roach } 239389266c0SGreg Roach if ($generation < $this->dgenerations) { 240389266c0SGreg Roach if (!empty($children)) { 241389266c0SGreg Roach // real people 242389266c0SGreg Roach echo '<table cellspacing="0" cellpadding="0" border="0" >'; 243389266c0SGreg Roach foreach ($children as $i => $child) { 244389266c0SGreg Roach echo '<tr><td>'; 245389266c0SGreg Roach $kids = $this->printDescendency($generation + 1, $child); 246389266c0SGreg Roach $numkids += $kids; 247389266c0SGreg Roach echo '</td>'; 248389266c0SGreg Roach // Print the lines 249389266c0SGreg Roach if (count($children) > 1) { 250389266c0SGreg Roach if ($i === 0) { 251389266c0SGreg Roach // Adjust for the first column on left 252389266c0SGreg Roach $h = round(((($this->box->height) * $kids) + 8) / 2); // Assumes border = 1 and padding = 3 253389266c0SGreg Roach // Adjust for other vertical columns 254389266c0SGreg Roach if ($kids > 1) { 255389266c0SGreg Roach $h = ($kids - 1) * 4 + $h; 256389266c0SGreg Roach } 257389266c0SGreg Roach echo '<td class="align-bottom">', 258389266c0SGreg Roach '<img id="vline_', $child->xref(), '" src="', Theme::theme()->parameter('image-vline'), '" width="3" height="', $h - 4, '"></td>'; 259389266c0SGreg Roach } elseif ($i === count($children) - 1) { 260389266c0SGreg Roach // Adjust for the first column on left 261389266c0SGreg Roach $h = round(((($this->box->height) * $kids) + 8) / 2); 262389266c0SGreg Roach // Adjust for other vertical columns 263389266c0SGreg Roach if ($kids > 1) { 264389266c0SGreg Roach $h = ($kids - 1) * 4 + $h; 265389266c0SGreg Roach } 266389266c0SGreg Roach echo '<td class="align-top">', 267389266c0SGreg Roach '<img class="bvertline" width="3" id="vline_', $child->xref(), '" src="', Theme::theme()->parameter('image-vline'), '" height="', $h - 2, '"></td>'; 268389266c0SGreg Roach } else { 269389266c0SGreg Roach echo '<td class="align-bottomm"style="background: url(', Theme::theme()->parameter('image-vline'), ');">', 270389266c0SGreg Roach '<img class="spacer" width="3" src="', Theme::theme()->parameter('image-spacer'), '"></td>'; 271389266c0SGreg Roach } 272389266c0SGreg Roach } 273389266c0SGreg Roach echo '</tr>'; 274389266c0SGreg Roach } 275389266c0SGreg Roach echo '</table>'; 276389266c0SGreg Roach } else { 277389266c0SGreg Roach // Hidden/empty boxes - to preserve the layout 278389266c0SGreg Roach echo '<table cellspacing="0" cellpadding="0" border="0" ><tr><td>'; 279389266c0SGreg Roach $numkids += $this->printDescendency($generation + 1, null); 280389266c0SGreg Roach echo '</td></tr></table>'; 281389266c0SGreg Roach } 282389266c0SGreg Roach echo '</td>'; 283389266c0SGreg Roach echo '<td>'; 284389266c0SGreg Roach } 285389266c0SGreg Roach 286389266c0SGreg Roach if ($numkids === 0.0) { 287389266c0SGreg Roach $numkids = 1; 288389266c0SGreg Roach } 289389266c0SGreg Roach echo '<table cellspacing="0" cellpadding="0" border="0" ><tr><td>'; 290389266c0SGreg Roach if ($person instanceof Individual) { 291389266c0SGreg Roach echo FunctionsPrint::printPedigreePerson($person); 292389266c0SGreg Roach echo '</td><td>', 293389266c0SGreg Roach '<img class="linef1" src="', Theme::theme()->parameter('image-hline'), '" width="8" height="3">'; 294389266c0SGreg Roach } else { 295389266c0SGreg Roach echo '<div style="width:', $this->box->width + 19, 'px; height:', $this->box->height + 8, 'px;"></div>', 296389266c0SGreg Roach '</td><td>'; 297389266c0SGreg Roach } 298389266c0SGreg Roach 299389266c0SGreg Roach // Print the spouse 300389266c0SGreg Roach if ($generation === 1 && $person instanceof Individual) { 301389266c0SGreg Roach if ($this->show_spouse) { 302389266c0SGreg Roach foreach ($person->getSpouseFamilies() as $family) { 303389266c0SGreg Roach $spouse = $family->getSpouse($person); 304389266c0SGreg Roach echo '</td></tr><tr><td>'; 305389266c0SGreg Roach echo FunctionsPrint::printPedigreePerson($spouse); 306389266c0SGreg Roach $numkids += 0.95; 307389266c0SGreg Roach echo '</td><td>'; 308389266c0SGreg Roach } 309389266c0SGreg Roach } 310389266c0SGreg Roach } 311389266c0SGreg Roach echo '</td></tr></table>'; 312389266c0SGreg Roach echo '</td></tr>'; 313389266c0SGreg Roach echo '</table>'; 314389266c0SGreg Roach 315389266c0SGreg Roach return $numkids; 316389266c0SGreg Roach } 317389266c0SGreg Roach 318389266c0SGreg Roach /** 319389266c0SGreg Roach * Prints pedigree of the person passed in 320389266c0SGreg Roach * 321389266c0SGreg Roach * @param Individual $person 322389266c0SGreg Roach * @param int $count 323389266c0SGreg Roach * 324389266c0SGreg Roach * @return void 325389266c0SGreg Roach */ 326389266c0SGreg Roach private function printPersonPedigree($person, $count) 327389266c0SGreg Roach { 328389266c0SGreg Roach if ($count >= $this->generations) { 329389266c0SGreg Roach return; 330389266c0SGreg Roach } 331389266c0SGreg Roach 332389266c0SGreg Roach $genoffset = $this->generations; // handle pedigree n generations lines 333389266c0SGreg Roach //-- calculate how tall the lines should be 334389266c0SGreg Roach $lh = ($this->bhalfheight) * (2 ** ($genoffset - $count - 1)); 335389266c0SGreg Roach // 336389266c0SGreg Roach //Prints empty table columns for children w/o parents up to the max generation 337389266c0SGreg Roach //This allows vertical line spacing to be consistent 338389266c0SGreg Roach if (count($person->getChildFamilies()) == 0) { 339389266c0SGreg Roach echo '<table cellspacing="0" cellpadding="0" border="0" >'; 340389266c0SGreg Roach $this->printEmptyBox(); 341389266c0SGreg Roach 342389266c0SGreg Roach //-- recursively get the father’s family 343389266c0SGreg Roach $this->printPersonPedigree($person, $count + 1); 344389266c0SGreg Roach echo '</td><td></tr>'; 345389266c0SGreg Roach $this->printEmptyBox(); 346389266c0SGreg Roach 347389266c0SGreg Roach //-- recursively get the mother’s family 348389266c0SGreg Roach $this->printPersonPedigree($person, $count + 1); 349389266c0SGreg Roach echo '</td><td></tr></table>'; 350389266c0SGreg Roach } 351389266c0SGreg Roach 352389266c0SGreg Roach // Empty box section done, now for regular pedigree 353389266c0SGreg Roach foreach ($person->getChildFamilies() as $family) { 354389266c0SGreg Roach echo '<table cellspacing="0" cellpadding="0" border="0" ><tr><td class="align-bottom">'; 355389266c0SGreg Roach // Determine line height for two or more spouces 356389266c0SGreg Roach // And then adjust the vertical line for the root person only 357389266c0SGreg Roach $famcount = 0; 358389266c0SGreg Roach if ($this->show_spouse) { 359389266c0SGreg Roach // count number of spouses 360389266c0SGreg Roach $famcount += count($person->getSpouseFamilies()); 361389266c0SGreg Roach } 362389266c0SGreg Roach $savlh = $lh; // Save current line height 363389266c0SGreg Roach if ($count == 1 && $genoffset <= $famcount) { 364389266c0SGreg Roach $linefactor = 0; 365389266c0SGreg Roach // genoffset of 2 needs no adjustment 366389266c0SGreg Roach if ($genoffset > 2) { 367389266c0SGreg Roach $tblheight = $this->box->height + 8; 368389266c0SGreg Roach if ($genoffset == 3) { 369389266c0SGreg Roach if ($famcount == 3) { 370389266c0SGreg Roach $linefactor = $tblheight / 2; 371389266c0SGreg Roach } elseif ($famcount > 3) { 372389266c0SGreg Roach $linefactor = $tblheight; 373389266c0SGreg Roach } 374389266c0SGreg Roach } 375389266c0SGreg Roach if ($genoffset == 4) { 376389266c0SGreg Roach if ($famcount == 4) { 377389266c0SGreg Roach $linefactor = $tblheight; 378389266c0SGreg Roach } elseif ($famcount > 4) { 379389266c0SGreg Roach $linefactor = ($famcount - $genoffset) * ($tblheight * 1.5); 380389266c0SGreg Roach } 381389266c0SGreg Roach } 382389266c0SGreg Roach if ($genoffset == 5) { 383389266c0SGreg Roach if ($famcount == 5) { 384389266c0SGreg Roach $linefactor = 0; 385389266c0SGreg Roach } elseif ($famcount > 5) { 386389266c0SGreg Roach $linefactor = $tblheight * ($famcount - $genoffset); 387389266c0SGreg Roach } 388389266c0SGreg Roach } 389389266c0SGreg Roach } 390389266c0SGreg Roach $lh = (($famcount - 1) * ($this->box->height) - ($linefactor)); 391389266c0SGreg Roach if ($genoffset > 5) { 392389266c0SGreg Roach $lh = $savlh; 393389266c0SGreg Roach } 394389266c0SGreg Roach } 395389266c0SGreg Roach echo '<img class="line3 pvline" src="', Theme::theme()->parameter('image-vline'), '" width="3" height="', $lh, '"></td>', 396389266c0SGreg Roach '<td>', 397389266c0SGreg Roach '<img class="linef2" src="', Theme::theme()->parameter('image-hline'), '" height="3"></td>', 398389266c0SGreg Roach '<td>'; 399389266c0SGreg Roach $lh = $savlh; // restore original line height 400389266c0SGreg Roach //-- print the father box 401389266c0SGreg Roach echo FunctionsPrint::printPedigreePerson($family->getHusband()); 402389266c0SGreg Roach echo '</td>'; 403389266c0SGreg Roach if ($family->getHusband()) { 404389266c0SGreg Roach echo '<td>'; 405389266c0SGreg Roach //-- recursively get the father’s family 406389266c0SGreg Roach $this->printPersonPedigree($family->getHusband(), $count + 1); 407389266c0SGreg Roach echo '</td>'; 408389266c0SGreg Roach } else { 409389266c0SGreg Roach echo '<td>'; 410389266c0SGreg Roach if ($genoffset > $count) { 411389266c0SGreg Roach echo '<table cellspacing="0" cellpadding="0" border="0" >'; 412389266c0SGreg Roach for ($i = 1; $i < (pow(2, ($genoffset) - $count) / 2); $i++) { 413389266c0SGreg Roach $this->printEmptyBox(); 414389266c0SGreg Roach echo '</tr>'; 415389266c0SGreg Roach } 416389266c0SGreg Roach echo '</table>'; 417389266c0SGreg Roach } 418389266c0SGreg Roach } 419389266c0SGreg Roach echo '</tr><tr>', 420389266c0SGreg Roach '<td class="align-top"><img class="pvline" alt="" role="presentation" src="', Theme::theme()->parameter('image-vline'), '" width="3" height="', $lh, '"></td>', 421389266c0SGreg Roach '<td><img class="linef3" alt="" role="presentation" src="', Theme::theme()->parameter('image-hline'), '" height="3"></td>', 422389266c0SGreg Roach '<td>'; 423389266c0SGreg Roach //-- print the mother box 424389266c0SGreg Roach echo FunctionsPrint::printPedigreePerson($family->getWife()); 425389266c0SGreg Roach echo '</td>'; 426389266c0SGreg Roach if ($family->getWife()) { 427389266c0SGreg Roach echo '<td>'; 428389266c0SGreg Roach //-- recursively print the mother’s family 429389266c0SGreg Roach $this->printPersonPedigree($family->getWife(), $count + 1); 430389266c0SGreg Roach echo '</td>'; 431389266c0SGreg Roach } else { 432389266c0SGreg Roach echo '<td>'; 433389266c0SGreg Roach if ($count < $genoffset - 1) { 434389266c0SGreg Roach echo '<table cellspacing="0" cellpadding="0" border="0" >'; 435389266c0SGreg Roach for ($i = 1; $i < (pow(2, ($genoffset - 1) - $count) / 2) + 1; $i++) { 436389266c0SGreg Roach $this->printEmptyBox(); 437389266c0SGreg Roach echo '</tr>'; 438389266c0SGreg Roach $this->printEmptyBox(); 439389266c0SGreg Roach echo '</tr>'; 440389266c0SGreg Roach } 441389266c0SGreg Roach echo '</table>'; 442389266c0SGreg Roach } 443389266c0SGreg Roach } 444389266c0SGreg Roach echo '</tr>', 445389266c0SGreg Roach '</table>'; 446389266c0SGreg Roach break; 447389266c0SGreg Roach } 448389266c0SGreg Roach } 449389266c0SGreg Roach 450389266c0SGreg Roach /** 451389266c0SGreg Roach * Calculates number of generations a person has 452e6562982SGreg Roach * 453e6562982SGreg Roach * @param Individual $individual 454389266c0SGreg Roach * @param int $depth 455e6562982SGreg Roach * 456389266c0SGreg Roach * @return int 457e6562982SGreg Roach */ 458389266c0SGreg Roach private function maxDescendencyGenerations(Individual $individual, $depth): int 459e6562982SGreg Roach { 460389266c0SGreg Roach if ($depth > $this->generations) { 461389266c0SGreg Roach return $depth; 462389266c0SGreg Roach } 463389266c0SGreg Roach $maxdc = $depth; 464389266c0SGreg Roach foreach ($individual->getSpouseFamilies() as $family) { 465389266c0SGreg Roach foreach ($family->getChildren() as $child) { 466389266c0SGreg Roach $dc = $this->maxDescendencyGenerations($child, $depth + 1); 467389266c0SGreg Roach if ($dc >= $this->generations) { 468389266c0SGreg Roach return $dc; 469389266c0SGreg Roach } 470389266c0SGreg Roach if ($dc > $maxdc) { 471389266c0SGreg Roach $maxdc = $dc; 472389266c0SGreg Roach } 473389266c0SGreg Roach } 474389266c0SGreg Roach } 475389266c0SGreg Roach $maxdc++; 476389266c0SGreg Roach if ($maxdc == 1) { 477389266c0SGreg Roach $maxdc++; 478389266c0SGreg Roach } 479389266c0SGreg Roach 480389266c0SGreg Roach return $maxdc; 481389266c0SGreg Roach } 482389266c0SGreg Roach 483389266c0SGreg Roach /** 484389266c0SGreg Roach * Print empty box 485389266c0SGreg Roach * 486389266c0SGreg Roach * @return void 487389266c0SGreg Roach */ 488389266c0SGreg Roach 489389266c0SGreg Roach private function printEmptyBox() 490389266c0SGreg Roach { 491389266c0SGreg Roach echo Theme::theme()->individualBoxEmpty(); 492389266c0SGreg Roach } 493389266c0SGreg Roach 494389266c0SGreg Roach /** 495389266c0SGreg Roach * Print a “Family Book” for an individual 496389266c0SGreg Roach * 497389266c0SGreg Roach * @param Individual $person 498389266c0SGreg Roach * @param int $descent_steps 499389266c0SGreg Roach * 500389266c0SGreg Roach * @return void 501389266c0SGreg Roach */ 502389266c0SGreg Roach private function printFamilyBook(Individual $person, $descent_steps) 503389266c0SGreg Roach { 504389266c0SGreg Roach if ($descent_steps == 0) { 505389266c0SGreg Roach return; 506389266c0SGreg Roach } 507389266c0SGreg Roach 508389266c0SGreg Roach echo 509389266c0SGreg Roach '<h3>', 510389266c0SGreg Roach /* I18N: %s is an individual’s name */ 511389266c0SGreg Roach I18N::translate('Family of %s', $person->getFullName()), 512389266c0SGreg Roach '</h3>', 513389266c0SGreg Roach '<table cellspacing="0" cellpadding="0" border="0" ><tr><td class="align-middle">'; 514389266c0SGreg Roach $this->dgenerations = $this->generations; 515389266c0SGreg Roach $this->printDescendency(1, $person); 516389266c0SGreg Roach echo '</td><td class="align-middle">'; 517389266c0SGreg Roach $this->printPersonPedigree($person, 1); 518389266c0SGreg Roach echo '</td></tr></table><br><br><hr class="family-break"><br><br>'; 519389266c0SGreg Roach foreach ($person->getSpouseFamilies() as $family) { 520389266c0SGreg Roach foreach ($family->getChildren() as $child) { 521389266c0SGreg Roach $this->printFamilyBook($child, $descent_steps - 1); 522389266c0SGreg Roach } 523389266c0SGreg Roach } 524e6562982SGreg Roach } 525168ff6f3Sric2016} 526