home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / Misc / FTREE0.3.LHA / ftree / src / RCS / layout.c,v < prev    next >
Encoding:
Text File  |  1994-04-29  |  103.0 KB  |  4,622 lines

  1. head    1.9;
  2. access;
  3. symbols
  4.     stage1:1.6;
  5. locks; strict;
  6. comment    @ * @;
  7.  
  8.  
  9. 1.9
  10. date    94.04.29.23.46.46;    author peteric;    state Exp;
  11. branches;
  12. next    1.8;
  13.  
  14. 1.8
  15. date    94.04.27.11.37.54;    author peteric;    state Exp;
  16. branches;
  17. next    1.7;
  18.  
  19. 1.7
  20. date    94.03.26.11.28.03;    author peteric;    state Exp;
  21. branches;
  22. next    1.6;
  23.  
  24. 1.6
  25. date    94.03.10.21.28.26;    author peteric;    state Exp;
  26. branches;
  27. next    1.5;
  28.  
  29. 1.5
  30. date    94.03.07.13.00.31;    author peteric;    state Exp;
  31. branches;
  32. next    1.4;
  33.  
  34. 1.4
  35. date    94.03.07.12.44.14;    author peteric;    state Exp;
  36. branches;
  37. next    1.3;
  38.  
  39. 1.3
  40. date    94.03.01.23.23.01;    author peteric;    state Exp;
  41. branches;
  42. next    1.2;
  43.  
  44. 1.2
  45. date    94.02.27.19.32.55;    author peteric;    state Exp;
  46. branches;
  47. next    1.1;
  48.  
  49. 1.1
  50. date    94.02.17.23.50.21;    author peteric;    state Exp;
  51. branches;
  52. next    ;
  53.  
  54.  
  55. desc
  56. @Layout tools for ftree family tree formatter.
  57. @
  58.  
  59.  
  60. 1.9
  61. log
  62. @Fixed problem with the first marriage not being correctly
  63. linked in, so an intitial multiple marriage wouldn't get
  64. displayed correctly. Fixed bug in do_simple_layout and removed
  65. a now-redundant debug message (At least I hope it's redundant!)
  66. @
  67. text
  68. @/*************************************************************************
  69.  *
  70.  *     $RCSfile: layout.c,v $
  71.  *
  72.  *    $Author: peteric $
  73.  *
  74.  *    $Date: 1994/04/27 11:37:54 $
  75.  *
  76.  *    $State: Exp $
  77.  *
  78.  *    $Revision: 1.8 $
  79.  *
  80.  *    Purpose:    Layout routines for ftree.
  81.  *            
  82.  *    $Log: layout.c,v $
  83.  * Revision 1.8  1994/04/27  11:37:54  peteric
  84.  * Fixed up the code to deal correctly with multiple marriages.
  85.  * Added a number of debugging statements and removed some of
  86.  * the redundant code - set_left_links etc. replacing them with
  87.  * the mirror_right_links code. As a result, findleft_back()
  88.  * and findleft_forw() can go too.
  89.  * Major changes result from the fact that some pointers can now
  90.  * point at marriage_t's or person_t's.
  91.  * Finally, added a routine check_links to check that the pointer
  92.  * referenced are valid and, where possible to check, correct. This
  93.  * is conditional on CHECK_LINKS being defined, and is not currently
  94.  * called.
  95.  *
  96.  * Revision 1.7  1994/03/26  11:28:03  peteric
  97.  * Included multiple-marriage support.
  98.  *
  99.  * Revision 1.6  1994/03/10  21:28:26  peteric
  100.  * Multiple pages working!
  101.  *
  102.  * Revision 1.5  1994/03/07  13:00:31  peteric
  103.  * Reduced stringwidth const.
  104.  *
  105.  * Revision 1.4  1994/03/07  12:44:14  peteric
  106.  * Passed on as first Version.
  107.  *
  108.  * Revision 1.3  1994/03/01  23:23:01  peteric
  109.  * changes to complete layered adjustment of position
  110.  * including auto-centering of parents.
  111.  *
  112.  * Revision 1.2  1994/02/27  19:32:55  peteric
  113.  * fixed layout problems of previous versions.
  114.  *
  115.  * Revision 1.1  1994/02/17  23:50:21  peteric
  116.  * Initial revision
  117.  *
  118.  *
  119.  *************************************************************************/
  120.  
  121.  
  122. #include <stdio.h>
  123. #include <stdlib.h>
  124. #include <sys/time.h>
  125. #include <string.h>
  126. #include <assert.h>
  127.  
  128. #include "ftree.h"
  129.  
  130. /*
  131.  * maximum number of times adjust_layout will attempt to get the
  132.  * layout right. After this, it just gives up...
  133.  */
  134. #define MAX_ADJUSTS    100
  135.  
  136. static pmheader_t *findright_back(marriage_t *marriage, int level);
  137. static pmheader_t *findright_forw(marriage_t *marriage, int level);
  138. static void set_right_links(options_t *, marriage_t *, int);
  139. static void do_layout_part2(options_t *opts, marriage_t *, int level);
  140. static void find_boundingbox(options_t *opts, marriage_t *m);
  141. static void normalise_area(options_t *opts, marriage_t *m);
  142. static void check_parents(pmheader_t *person);
  143. pmheader_t * mof(pmheader_t *p, enum xpspec_t spec);
  144. static void mirror_right_links(options_t *opts);
  145. static int linkedto(pmheader_t *last, pmheader_t *this);
  146. static char *nameof(pmheader_t *this);
  147. void move_marriage(marriage_t *marriage, int dx);
  148. #ifdef SHOW_LAYOUT
  149. static void adjust_layout(FILE *outf, options_t *opts, marriage_t *startm);
  150. #else
  151. static void adjust_layout(options_t *opts);
  152. #endif
  153. #ifdef DEBUG
  154. static void show_generations(void);
  155. #ifdef CHECK_LINKS
  156. void check_links(void);
  157. #endif
  158. #endif
  159. extern char *strdup(const char*);
  160.  
  161. /*(
  162.  ********************************************************************************** 
  163.  *
  164.  *    Function:    print
  165.  *
  166.  *
  167.  *    Inputs:
  168.  *        opts
  169.  *
  170.  *    Outputs:
  171.  *        (file)
  172.  *
  173.  *    Error Handling:
  174.  *        none.
  175.  *
  176.  *    Description:
  177.  *        
  178.  * Calls the routines to format and output PostScript statements which will draw
  179.  * the family tree described in the opts array, using data from the mroot/proot
  180.  * lists.
  181.  * 
  182.  * The tree is assumed to be a true tree - i.e. one root node branching out to n
  183.  * leaf nodes. 
  184.  * 
  185.  * If the named 'outputfile' is 'con' this is taken as a signal to write output to
  186.  * the standard output stream instead of opening a new file.
  187.  * 
  188.  ********************************************************************************** 
  189. )*/
  190.  
  191. void print(options_t *opts)
  192. {
  193.     FILE *outf;
  194.     int i, sx, sy;
  195.     marriage_t *startmarriage;
  196.  
  197.     if (strcmp(opts->outputfile, "-"))
  198.     {
  199.         outf = fopen(opts->outputfile, "w");
  200.         if (outf == NULL)
  201.         {
  202.             fprintf(stderr, "ftree: cannot write file '%s'\n", opts->outputfile);
  203.             exit(1);
  204.         }
  205.     }
  206.     else
  207.         outf = stdout;
  208.  
  209.     /*
  210.      * set things up...
  211.      */
  212.     sx = (opts->pagewidth - opts->rmargin)/2;
  213.     sy = opts->titlefont.linespc + 3*opts->personfont.linespc;
  214.     startmarriage = findfirstmarriage(opts->startperson);
  215.     for (i = 0; i < MAXLEVELS; i++)
  216.         generation[i].first = generation[i].last = NULL;
  217.     
  218.     dbprintf(("\n----------------------------------- do_simple_layout -----------------------------------------------\n"));
  219.     
  220.     /*
  221.      * lay out our tree
  222.      */
  223.     do_simple_layout(opts, startmarriage, sx, sy, 0);
  224.         
  225.     dbprintf(("\n----------------------------------- do_layout_part2 ------------------------------------------------\n"));
  226.  
  227.     /*
  228.      * now the layout is set, set up the left & right pointers in
  229.      * the person records so that the set_links routines have something
  230.      * to work on.
  231.      */
  232.     do_layout_part2(opts, startmarriage, 0);
  233.  
  234.     dbprintf(("\n----------------------------------- set_left/right_links -------------------------------------------\n"));
  235.  
  236.     /*
  237.      * set up the left & right links from the generation array
  238.      * into the main structure.
  239.      */
  240.     generation[0].first = (pmheader_t*)startmarriage;
  241.     nlevels = 1;
  242.     set_right_links(opts, startmarriage, 1);
  243.  
  244.     /*
  245.      * create the right links.
  246.      */
  247.     mirror_right_links(opts);
  248.     
  249. #ifdef DEBUG
  250.     dbprintf(("\n----------------------------------- show_generations -----------------------------------------------\n"));
  251.     
  252.     show_generations();
  253. #endif
  254.  
  255.     dbprintf(("\n----------------------------------- adjust_layout --------------------------------------------------\n"));
  256.  
  257.     /*
  258.      * use the links to adjust the gap btw. people on a line.
  259.      */
  260. #ifdef SHOW_LAYOUT
  261.     do_prolog(outf, opts);
  262.     do_title(outf, opts, startmarriage);
  263.     print_tree(outf, opts, startmarriage);
  264.     adjust_layout(outf, opts, startmarriage);
  265.     print_tree(outf, opts, startmarriage);
  266. #else
  267.     adjust_layout(opts);
  268.  
  269.     dbprintf(("\n----------------------------------- normalise_area -------------------------------------------------\n"));
  270.  
  271.     /*
  272.      * get the bounding box for the chart & use it to left-adjust the
  273.      * chart (so that the left of the chart is on page 1) and set up
  274.      * the PostScript BoundingBox comment.
  275.      */
  276.     normalise_area(opts, startmarriage);
  277.     
  278.     dbprintf(("\n----------------------------------- do_prolog ------------------------------------------------------\n"));
  279.  
  280.     /*
  281.      * print out the PostScript DSC prolog stuff
  282.      */
  283.     do_prolog(outf, opts);
  284.     
  285.     dbprintf(("\n----------------------------------- do_title -------------------------------------------------------\n"));
  286.  
  287.     /*
  288.      * put a title on the page
  289.      */
  290.     do_title(outf, opts, startmarriage);
  291.     
  292.     dbprintf(("\n----------------------------------- print_tree -----------------------------------------------------\n"));
  293.  
  294.     /*
  295.      * print our tree
  296.      */
  297.     print_tree(outf, opts, startmarriage);
  298. #endif
  299.     
  300.     dbprintf(("\n----------------------------------- do_epilog ------------------------------------------------------\n"));
  301.  
  302.     /*
  303.      * finish it off
  304.      */
  305.     do_epilog(outf, opts);
  306.  
  307.     /*
  308.      * close the file.
  309.      */
  310.     if (outf != stdout)
  311.         fclose(outf);
  312.     else
  313.         fflush(outf);
  314. }
  315.  
  316. /*(
  317.  ********************************************************************************** 
  318.  *
  319.  *    Function:    do_simple_layout
  320.  *
  321.  *
  322.  *    Inputs:
  323.  *        opts - current option settings
  324.  *        id - id of person
  325.  *        x, y - initial placement of marriage
  326.  *
  327.  *    Outputs:
  328.  *        none.
  329.  *
  330.  *    Error Handling:
  331.  *        none.
  332.  *
  333.  *    Description:
  334.  *        
  335.  * Determines the initial placement of the marriage(s) connected to 'id' and those
  336.  * marriages made by their children.  This initial placement ignores issues of
  337.  * overlap; this is dealt with later. The main element here is the general x
  338.  * placement, calculation of y placement, and the setting up of various values in
  339.  * the person_t and marriage_t structures.
  340.  * 
  341.  ********************************************************************************** 
  342. )*/
  343.  
  344. void do_simple_layout(options_t *opts, marriage_t *marriage, int x, int y, int level)
  345. {
  346.     int children;
  347.     int ptwidth, startx, childy;
  348.     person_t *child;
  349.     marriage_t *m;
  350.     
  351.     dbprintf(( "\ndo_simple_layout: do layout level %d\n", level));
  352.  
  353.     while(marriage)
  354.     {
  355.         dbprintf(( "do_simple_layout: set marriage %s at %d x %d.\n", nameof((pmheader_t*)marriage), x, y));
  356.         marriage->h.xpos = x;
  357.         marriage->h.ypos = y;
  358.         if (marriage->next)
  359.             marriage->h.right = (pmheader_t *)marriage->next;
  360.         assert(marriage->h.width != 0);
  361.  
  362.         /*
  363.          * calculate various child<->parent figures - e.g the width of
  364.          * the children's line, and make various relationship links.
  365.          */
  366.         children = 0;
  367.         ptwidth = 0;
  368.         child = marriage->firstchild;
  369.         while(child != NULL)
  370.         {
  371.             children++;
  372.             dbprintf(( "do_simple_layout: setting up child %d (%s)\n", children, child->firstname));
  373.             m = findfirstmarriage(child->id);
  374.             child->firstmarriage = m;
  375.             child->lastmarriage = m;
  376.             
  377.             assert((m != NULL && child->married) || (m == NULL && !child->married));
  378.             
  379.             while(m)
  380.             {
  381.                 /*
  382.                  * this should perhaps be outside the loop?
  383.                  */
  384.                 m->backlink = marriage;
  385.                 dbprintf(("do_simple_layout: setting backlink for child marriage %s to marriage %s\n",
  386.                         nameof((pmheader_t*)child->firstmarriage), nameof((pmheader_t*)marriage) ));
  387.                 
  388.                 ptwidth += m->h.width;
  389.                 m->h.right = (pmheader_t *)m->next;
  390.                 
  391.                 /*
  392.                  * want to remember the last marriage - this will
  393.                  * get overwritten until m->next is NULL.
  394.                  */
  395.                 child->lastmarriage = m;
  396.                 m = m->next;
  397.             }
  398.             /*
  399.              * this bit of trickery is so that we recalculate the child's width
  400.              * if we  change fullname because the parent's names are different.
  401.              * We already coped with it if married was set.
  402.              */
  403.             child->fullname = !streq(child->family, marriage->husband->family);
  404.             if (child->fullname)
  405.                 child->h.width = widthof(opts, child);
  406.             child->fullname |= child->married;
  407.             child->h.level = level + 1;
  408.  
  409.             dbprintf(( "do_simple_layout: child setup ... 2\n"));
  410.             /*
  411.              * set up the level pointers (right side only required).
  412.              */
  413.             if (child->married)
  414.             {
  415.                 if (child->nextchild)
  416.                     child->lastmarriage->h.right = mof((pmheader_t*)child->nextchild, XP_FIRST);
  417.                 else
  418.                     child->lastmarriage->h.right = NULL;
  419.  
  420.                 if (child->lastchild)
  421.                 {
  422.                     if (child->lastchild->married)
  423.                         child->lastchild->lastmarriage->h.right = (pmheader_t *)child->firstmarriage;
  424.                     else
  425.                         child->lastchild->h.right = (pmheader_t *)child->firstmarriage;
  426.                     child->lastchild->h.right = (pmheader_t*)child->firstmarriage;
  427.                 }
  428.                 child->h.right = NULL;
  429.             }
  430.             else
  431.             {
  432.                 ptwidth += child->h.width;
  433.                 if (child->nextchild)
  434.                     child->h.right = mof((pmheader_t*)child->nextchild, XP_FIRST);
  435.                 else
  436.                     child->h.right = NULL;
  437.             }
  438.             dbprintf(( "do_simple_layout: child setup ... 3\n"));
  439.  
  440.             child = child->nextchild;
  441.         }
  442.         dbprintf(( "do_simple_layout: finished child setup\n"));
  443.         marriage->children = children;
  444.         marriage->h.level = level;
  445.  
  446.         /*
  447.          * ptwidth is only the width of the connecting line ... it doesn't
  448.          * include the space at each end.
  449.          */
  450.         if (marriage->children >= 1)
  451.         {
  452.             ptwidth -= (pwidthof((pmheader_t*)marriage->firstchild, XP_FIRST) +
  453.                 pwidthof((pmheader_t*)marriage->lastchild, XP_FIRST)) / 2;
  454.         }
  455.         dbprintf(( "do_simple_layout: ptwidth: %d children %d\n", ptwidth, marriage->children));
  456.  
  457.         if (marriage->children > 0)
  458.         {
  459.             childy = y + opts->vspace;
  460.             switch (marriage->hint)
  461.             {
  462.                 case H_RIGHT:
  463.                     startx = x - (ptwidth * 0.25);
  464.                     break;
  465.                 case H_LEFT:
  466.                     startx = x - (ptwidth * 0.75);
  467.                     break;
  468.                 default:
  469.                 case H_CENTERED:
  470.                     startx = x - (ptwidth * 0.5);
  471.                     break;
  472.             }
  473.             dbprintf(( "do_simple_layout: startx: %d (= %d - (%d/2)), childy: (%d + %d), children: %d\n",
  474.                         startx, x, ptwidth, y, opts->vspace, marriage->children));
  475.             
  476.             /*
  477.              * have a go at placing the children & their marriages
  478.              */
  479.             child = marriage->firstchild;
  480.             while(child != NULL)
  481.             {
  482.                 child->h.xpos = startx;
  483.                 child->h.ypos = childy;
  484.                 dbprintf(( "do_simple_layout: child %s @@ %dx%d\n", nameof((pmheader_t*)child), startx, childy));
  485.                 if (child->married)
  486.                 {
  487.                     m = child->firstmarriage;
  488.                     while(m)
  489.                     {
  490.                         m->h.xpos = startx;
  491.                         m->h.ypos = childy;
  492.                         if (m->next)
  493.                             startx += (m->h.width + m->next->h.width) / 2;
  494.                         else if (child->nextchild)
  495.                             startx += (m->h.width +
  496.                                 pwidthof((pmheader_t*)child->nextchild, XP_FIRST)) / 2;
  497.                         
  498.                         dbprintf(( "do_simple_layout:   marriage %s at %dx%d, next: %d\n",
  499.                                 nameof((pmheader_t*)m), m->h.xpos, m->h.ypos, startx));
  500.                         m = m->next;
  501.                     }
  502.                 }
  503.                 else if (child->nextchild)
  504.                     startx += (child->h.width +
  505.                         pwidthof((pmheader_t*)child->nextchild, XP_FIRST)) / 2;
  506.                 child = child->nextchild;
  507.             }
  508.  
  509.             dbprintf(( "do_simple_layout: searching for marriages \n"));
  510.  
  511.             child = marriage->firstchild;
  512.             while(child != NULL)
  513.             {
  514.                 if (child->married)
  515.                 {
  516.                     /*
  517.                      * these positions should be the child's ones.
  518.                      */
  519.                     do_simple_layout(opts, child->firstmarriage,
  520.                             child->h.xpos, child->h.ypos, level+1);
  521.                 }
  522.                 child = child->nextchild;
  523.             }
  524.         }
  525.         dbprintf(( "do_simple_layout: finished marriage.\n"));
  526.  
  527.         if (marriage->next)
  528.             x += (marriage->h.width + marriage->next->h.width) / 2;
  529.  
  530.         marriage = marriage->next;
  531.     }
  532.  
  533.     dbprintf(( "do_simple_layout: finished simple layout\n"));
  534. }
  535.  
  536. /*(
  537.  ***********************************************************************************
  538.  *
  539.  *    Function:    do_layout_part2
  540.  *
  541.  *
  542.  *    Inputs:
  543.  *        opts - options array
  544.  *        id - starting ID code.
  545.  *        level - generation/recursion level.
  546.  *
  547.  *    Outputs:
  548.  *        none.
  549.  *
  550.  *    Description:
  551.  *        
  552.  * Modifies the data structure by adding in the left and right pointers for inter-
  553.  * marriage links. Assumes that do_simple_layout has already been done, swhich
  554.  * sets up the in-marriage links between children and linked marriages.
  555.  * 
  556.  ***********************************************************************************
  557. )*/
  558.  
  559. static void do_layout_part2(options_t *opts, marriage_t *marriage, int level)
  560. {
  561.     pmheader_t *this;
  562.     person_t *child;
  563.     
  564.     dbprintf(( "\ndo_layout_part2: marriage level %d\n", level));
  565.  
  566.     if (marriage->children > 0)
  567.     {
  568.         child = marriage->firstchild;
  569.         while(child != NULL)
  570.         {
  571.             if (child->married)
  572.             {
  573.                 do_layout_part2(opts, child->firstmarriage, level + 1);
  574.             }
  575.             child = child->nextchild;
  576.         }
  577.     }
  578.  
  579.     /*
  580.      * fill in the NULL links that aren't done above. Must wait 'till all
  581.      * the backlinks etc. are done.
  582.      */
  583.     this = findright_back(marriage, level + 1);
  584.  
  585.     dbprintf(("do_layout_part2: findright lev %d returns %s, firstchild: %s\n",
  586.             level+1, nameof(this), nameof((pmheader_t*) marriage->firstchild) ));
  587.  
  588.     child = marriage->lastchild;
  589.  
  590.     if (child && child->married)
  591.         child->lastmarriage->h.right = this;
  592.     else if (child)
  593.         child->h.right = this;
  594.     else
  595.         dbprintf(("do_layout_part2: no firstchild to set up!\n"));
  596. }
  597.  
  598. /*(
  599.  ********************************************************************************** 
  600.  *
  601.  *    Function:    mirror_right_links
  602.  *
  603.  *
  604.  *    Inputs:
  605.  *        opts - global options arary
  606.  *
  607.  *    Outputs:
  608.  *        none.
  609.  *
  610.  *    Description:
  611.  *        
  612.  *        Create the doubly linked list from the singly linked left/right generation
  613.  * list for each generation.
  614.  *
  615.  ********************************************************************************** 
  616. )*/
  617.  
  618. static void mirror_right_links(options_t *opts)
  619. {
  620.     pmheader_t *next, *curr;
  621.     int i;
  622.     
  623.     dbprintf(("\nmirror_right_links: start"));
  624.  
  625.     /*
  626.      * generate the backlink 'right' for the left link 'left' for each
  627.      * node in the lists pointed to by the generation array.
  628.      */
  629.     for(i = 0; i < nlevels; i++)
  630.     {
  631.         curr = generation[i].first;
  632.         
  633.         dbprintf(("\nmirror_right_links: level %d: %s ",i,nameof(curr)));
  634.  
  635.         if (curr)    /* sanity check */
  636.         {
  637.             while(curr->right)
  638.             {
  639.                 next = curr->right;
  640.                 next->left = curr;
  641.                 curr = next;
  642.             }
  643.             generation[i].last = curr;
  644.         }
  645.     }
  646.  
  647.     dbprintf(("\nmirror_right_links: end\n"));
  648. }
  649.  
  650. /*(
  651.  ***********************************************************************************
  652.  *
  653.  *    Function:    find_boundingbox
  654.  *
  655.  *
  656.  *    Inputs:
  657.  *        opts - global options structure
  658.  *        id - id code identifying the initial point
  659.  *        level - generation/recursion level
  660.  *
  661.  *    Outputs:
  662.  *        none.
  663.  *
  664.  *    Description:
  665.  *
  666.  * Searches the tree looking for the extremities of the useful area. The area used
  667.  * by the tree is notionally 0,0 -> x,y, where x,y is the size required to print
  668.  * it, but the algorithm can end up with an area -a,-b -> x,y. This routine
  669.  * returns these values by comparing the current limit with the calculated size of
  670.  * all nodes found.
  671.  * 
  672.  * This is done in part with some macros which make life a little easier.
  673.  * 
  674. ***********************************************************************************
  675. )*/
  676.  
  677. #define set_low(var, val)    {if ((var) > (val)) (var) = (val); }
  678. #define set_high(var, val)    {if ((var) < (val)) (var) = (val); }
  679.  
  680. static void find_boundingbox(options_t *opts, marriage_t *marriage)
  681. {
  682.     person_t *p;
  683.     while (marriage)
  684.     {
  685.         dbprintf(("find_boundingbox: marriage %s & %s: ", nameof((pmheader_t*)marriage)));
  686.         
  687.         set_low(opts->bbly, marriage->h.ypos);
  688.         set_high(opts->bbuy, marriage->h.ypos);
  689.         set_low(opts->bblx, marriage->h.xpos - marriage->h.width / 2);
  690.         set_high(opts->bbux, marriage->h.xpos + marriage->h.width / 2);
  691.         
  692.         if (marriage->children > 0)
  693.         {
  694.             dbprintf(("child %s\n", marriage->firstchild->firstname));
  695.             p = marriage->firstchild;
  696.             while(p)
  697.             {
  698.                 if (p->married)
  699.                 {
  700.                     find_boundingbox(opts, p->firstmarriage);
  701.                 }
  702.                 else
  703.                 {
  704.                     set_low(opts->bbly, p->h.ypos);
  705.                     set_high(opts->bbuy, p->h.ypos);
  706.                     set_low(opts->bblx, p->h.xpos - p->h.width / 2);
  707.                     set_high(opts->bbux, p->h.xpos + p->h.width / 2);
  708.                 }
  709.                 p = p->nextchild;
  710.             }
  711.         }
  712.         else
  713.             dbprintf(("no children\n"));
  714.         
  715.         marriage = marriage->next;
  716.     }
  717. }
  718. #undef set_low
  719. #undef set_high
  720.  
  721. /*(
  722.  ***********************************************************************************
  723.  *
  724.  *    Function:    set_right_links
  725.  *
  726.  *
  727.  *    Inputs:
  728.  *        opts - global options structure
  729.  *        id - id code identifying the initial point
  730.  *        level - generation/recursion level
  731.  *
  732.  *    Outputs:
  733.  *        none.
  734.  *
  735.  *    Description:
  736.  *        
  737.  * Sets up generation[] array by scanning through the tree looking for leftmost
  738.  * people on a level which hasn't been defined yet. When found, the left pointer
  739.  * in the array is set to this person.
  740.  * 
  741.  ***********************************************************************************
  742. )*/
  743.  
  744. static void set_right_links(options_t *opts, marriage_t *marriage, int level)
  745. {
  746.     person_t *p;
  747.     
  748.     if (marriage == NULL)
  749.         return;
  750.     
  751.     while (marriage)
  752.     {
  753.         dbprintf(("set_right_links: marriage %s level %d: ",nameof((pmheader_t*)marriage), level));
  754.         
  755.         /*
  756.          * operate the generation array on a first-come-first-served
  757.          * basis, so we get the end points. We actually scan the whole
  758.          * tree, though.
  759.          */
  760.         if (generation[level].first == NULL)
  761.         {
  762.             generation[level].first = mof((pmheader_t*)marriage->firstchild, XP_FIRST);
  763.             dbprintf(("FIRST: "));
  764.         }
  765.         if (nlevels <= level)
  766.             nlevels = level+1;
  767.  
  768.         if (marriage->children > 0)
  769.         {
  770.             dbprintf(("child %s (lev: %d)\n",
  771.                 nameof((pmheader_t*)marriage->firstchild),marriage->firstchild->h.level));
  772.  
  773.             p = marriage->firstchild;
  774.             while(p)
  775.             {
  776.                 if (p->married)
  777.                 {
  778.                     set_right_links(opts, p->firstmarriage, level+1);
  779.                 }
  780.                 p = p->nextchild;
  781.             }
  782.         }
  783.         else
  784.             dbprintf(("no children\n"));
  785.     
  786.         marriage = marriage->next;
  787.     }
  788. }
  789.  
  790. /*(
  791.  ********************************************************************************** 
  792.  *
  793.  *    Function:    adjust_layout
  794.  *
  795.  *
  796.  *    Inputs:
  797.  *        opts - current option set
  798.  *        outf - output file [debug mode only]
  799.  *        startm - start marriage point [debug mode only]
  800.  *
  801.  *    Outputs:
  802.  *        (file)
  803.  *
  804.  *    Error Handling:
  805.  *        None.
  806.  *
  807.  *    Description:
  808.  *        
  809.  * This routine takes the initial positions assigned by the routine
  810.  * do_simple_layout and adjusts the positions such that people do not overlap.
  811.  *
  812.  * The following checks are performed:
  813.  *   1. That people do not overlap. This is done for all pairs of people.
  814.  *   2. That for any triple a,b,c of siblings where b is not married b is not
  815.  *      closer to a than c.
  816.  *   3. That for any oldest or youngest child the distance to the next sibling
  817.  *      is not greater than necessary. i.e. given siblings a b c d, that the
  818.  *      distance b - a is not greater than the half the sum of the widths of a and
  819.  *      b, and similarly for c and d. This is only done if a anc d are single.
  820.  *   4. When any person is moved, the parents' location is checkedto ensure that
  821.  *      they remain centered.
  822.  * 
  823.  **********************************************************************************
  824. )*/
  825.  
  826. #ifdef SHOW_LAYOUT
  827. static void adjust_layout(FILE *outf, options_t *opts, marriage_t *startm)
  828. #else
  829. static void adjust_layout(options_t *opts)
  830. #endif
  831. {
  832.     int adjust_count, gen, dx, moved;
  833.     int move_parents = FALSE;
  834.     pmheader_t *this, *last;
  835. #define c_person        ((person_t *)this)
  836. #define c_marriage    ((marriage_t *)this)
  837. #define l_person    ((person_t *)last)
  838. #define l_marriage    ((marriage_t *)last)
  839.     person_t *p2;
  840.  
  841.     dbprintf(("adjust_layout: start\n"));
  842.     adjust_count = 0;
  843.     do
  844.     {
  845.         moved = FALSE;
  846.         for(gen = 0; gen < nlevels; gen++)
  847.         {
  848.             this = generation[gen].first;
  849.             last = NULL;
  850.             dbprintf(("adjust_layout: generation %d (starts with %s)\n", gen, nameof(this)));
  851.  
  852.             while(this)
  853.             {
  854.                 if (last != NULL)
  855.                 {
  856.                     int this_w, last_w, this_x, last_x;
  857.                     
  858.                     /*
  859.                      * check to see if they overlap. Overlapping
  860.                      * includes the area required to print the name
  861.                      * etc, hence the 'width' calculation.
  862.                      */
  863.                     this_x = xposof(this, XP_FIRST);
  864.                     last_x = xposof(last, XP_LAST);
  865.                     this_w = pwidthof(this, XP_FIRST);
  866.                     last_w = pwidthof(last, XP_LAST);
  867.                     
  868.                     dx = (this_x - last_x);
  869.                     dx -= ((this_w + last_w) / 2 );
  870.  
  871.                     dbprintf(("examining pair %s & %s (%d w: %d vs %d w: %d), dx = %d\n",
  872.                         nameof(last), nameof(this), last_x, last_w, this_x, this_w, dx));
  873.  
  874.                     if (dx < -1)
  875.                     {
  876.                         dx = - dx;
  877.  
  878.                         /*
  879.                          * move the people on this line by the ammount
  880.                          * these two overlap, plus the width of each side of
  881.                          * the area they occupy.
  882.                          */
  883.                         moved = TRUE;
  884.                         dbprintf(("adjust_layout: set moved true.\n"));
  885.  
  886.                         switch (this->type)
  887.                         {
  888.                             case HT_PERSON:
  889.                                 p2 = (person_t*)this;
  890.                                 while(p2)
  891.                                 {
  892.                                     move_tree(p2, dx);
  893.                                     p2 = p2->nextchild;
  894.  
  895.                                 }
  896.                                 move_parents = TRUE;
  897.                                 break;
  898.  
  899.                             case HT_MARRIAGE:
  900.                                 move_marriage(c_marriage, dx);
  901.                                 move_parents = TRUE;
  902.                                 break;
  903.                         }
  904.                     }
  905.                     else if (dx > 1 && linkedto(last, this))
  906.                     {
  907.                         /*
  908.                          * See if two siblings are unreasonably far apart
  909.                          * as a result of others moving.
  910.                          */
  911.                         if (last->type == HT_PERSON && l_person->lastchild == NULL && !l_person->married)
  912.                         {
  913.                             dbprintf(("adjust_layout: moving elder child %s closer to %s by %d\n",
  914.                                     nameof(last), nameof(this), dx));
  915.                             last->xpos += dx;
  916.                             dbprintf(("adjust_layout: set moved true.\n"));
  917.                             moved = TRUE;
  918.                             move_parents = TRUE;
  919.                         }
  920.                         if (this->type == HT_PERSON && c_person->nextchild == NULL && !c_person->married)
  921.                         {
  922.                             dbprintf(("adjust_layout: moving youngest child %s closer to %s by %d\n",
  923.                                     nameof(this), nameof(last), dx));
  924.                             this->xpos -= dx;
  925.                             dbprintf(("adjust_layout: set moved true.\n"));
  926.                             moved = TRUE;
  927.                             move_parents = TRUE;
  928.                         }
  929.                     }
  930.  
  931.                     if (linkedto(last, this))
  932.                     {
  933.                         /*
  934.                          * check that people don't get left squeezed up
  935.                          * when there's plenty of space elsewhere.
  936.                          */
  937.                         if (this->type == HT_PERSON && c_person->nextchild != NULL && !c_person->married)
  938.                         {
  939.                             person_t *nc;
  940.                             int dx2, diff;
  941.                             
  942.                             nc = c_person->nextchild;
  943.                             dx2 = xposof((pmheader_t*)nc, XP_FIRST) - this->xpos;
  944.                             dx2 -= ((c_person->h.width + pwidthof((pmheader_t*)nc, XP_FIRST)) / 2 );
  945.                             diff = dx2 - dx;
  946.                             dbprintf(("adjust_layout: check centering: %s <- %d -> %s <- %d -> %s  (out by: %d)\n",
  947.                                 nameof(last), dx, nameof(this), dx2, nameof((pmheader_t*)nc), diff / 2));
  948.                             if (diff > 1)
  949.                             {
  950.                                 dbprintf(("adjust_layout: right centering child %s by %d\n",
  951.                                         nameof(this), diff / 2));
  952.                                 this->xpos += diff / 2;
  953.                                 dbprintf(("adjust_layout: set moved true.\n"));
  954.                                 moved = TRUE;
  955.                             }
  956.                             else if (diff < -1)
  957.                             {
  958.                                 dbprintf(("adjust_layout: left centering child %s by %d\n",
  959.                                         nameof(this), diff / 2));
  960.                                 this->xpos += diff / 2;
  961.                                 dbprintf(("adjust_layout: set moved true.\n"));
  962.                                 moved = TRUE;
  963.                             }
  964.                         }
  965.                     }
  966.                     if (move_parents)
  967.                     {
  968.                         check_parents(this);
  969.                         move_parents = FALSE;
  970.                     }
  971.                 }
  972.  
  973.                 last = this;
  974.                 this = this->right;
  975.             }
  976.         }
  977.         if (moved)
  978.         {
  979.             dbprintf(("\nadjust_layout: rerun; people moved!\n\n"));
  980.         }
  981.         adjust_count++;
  982. #ifdef SHOW_LAYOUT
  983.         print_tree(outf, opts, startm);
  984.         fprintf(outf, "showpage\n");
  985. #endif
  986.     } while(moved && adjust_count < MAX_ADJUSTS);
  987.     if (adjust_count == MAX_ADJUSTS) 
  988.     {
  989.         fprintf(stderr, "adjust_layout: too much adjusting! - loop in layout.\n");
  990.     }
  991.     dbprintf_note(("adjust_layout: took %d tries to adjust layout.\n", adjust_count));
  992.     dbprintf(("adjust_layout: end\n"));
  993. #undef c_person
  994. #undef c_marriage
  995. #undef l_person
  996. #undef l_marriage
  997. }
  998.  
  999. /*(
  1000.  ********************************************************************************** 
  1001.  *
  1002.  *    Function:    check_parents
  1003.  *
  1004.  *
  1005.  *    Inputs:
  1006.  *        person - the person (or one of them) who has moved.
  1007.  *
  1008.  *    Outputs:
  1009.  *        int - flag set true if last & this linked.
  1010.  *
  1011.  *    Error Handling:
  1012.  *        none.
  1013.  *
  1014.  *    Description:
  1015.  *        
  1016.  * Check to see if the parents of the child referenced should be moved, as the
  1017.  * child has just been. Currently, this basically means ensure that the parents
  1018.  * are always centered above the children. Later the bias system used in
  1019.  * do_simple_layout might be more appropriate.
  1020.  *
  1021.  * This routine checks parents back to the tree's root using the backlink.
  1022.  * 
  1023.  ********************************************************************************** 
  1024. )*/
  1025.  
  1026. static void check_parents(pmheader_t *this)
  1027. {
  1028.     int dxp, xp, fc, lc;
  1029.     marriage_t *m = NULL;
  1030.  
  1031.     switch(this->type)
  1032.     {
  1033.         case HT_PERSON:
  1034.             m = ((person_t*)this)->parents;
  1035.             break;
  1036.  
  1037.         case HT_MARRIAGE:
  1038.             m = (marriage_t*)this;
  1039.             break;
  1040.     }
  1041.     
  1042.     while(m)
  1043.     {
  1044.         dbprintf(("check_parents: checking marriage %s\n", nameof((pmheader_t*)m) ));
  1045.  
  1046.         if (m->firstchild)
  1047.         {
  1048.             /*
  1049.              * get range of X used by children of this marriage...
  1050.              */
  1051.             fc = xposof((pmheader_t*)m->firstchild, XP_FIRST);
  1052.             lc = xposof((pmheader_t*)m->lastchild, XP_FIRST);
  1053.             dxp = fc - lc;
  1054.             if (dxp < 0)
  1055.                 dxp = - dxp;
  1056.             xp = fc + (dxp / 2);
  1057.             
  1058.             /*
  1059.              * and check that the marriage is decently centred.
  1060.              */
  1061.             if (abs(xp - m->h.xpos) > 1)
  1062.             {
  1063.                 dbprintf(("check_parents: children range %d to %d: move parents by %d to %d\n",
  1064.                         fc, lc, xp - m->h.xpos, xp));
  1065.                 m->h.xpos = xp;
  1066.             }
  1067.         }
  1068.         m = m->backlink;
  1069.     }
  1070. }
  1071.  
  1072. /*(
  1073.  ********************************************************************************** 
  1074.  *
  1075.  *    Function:    linkedto
  1076.  *
  1077.  *
  1078.  *    Inputs:
  1079.  *        last - a person to check who is left of 'this'
  1080.  *        this - a person to check right of 'last'
  1081.  *
  1082.  *    Outputs:
  1083.  *        int - flag set true if last & this linked.
  1084.  *
  1085.  *    Error Handling:
  1086.  *        none.
  1087.  *
  1088.  *    Description:
  1089.  *        
  1090.  * Check to see if the person referenced by 'last' and the person referenced by
  1091.  * 'this' are siblings, or, if they refer to marriages, are remarriages. Basically
  1092.  * return TRUE if these people are on the same line & are direct family.
  1093.  * 
  1094.  ********************************************************************************** 
  1095. )*/
  1096.  
  1097. static int linkedto(pmheader_t *last, pmheader_t *this)
  1098. {
  1099.     if (last->type == HT_PERSON)
  1100.         return ((person_t*)last)->nextchild == (person_t*)this;
  1101.     else
  1102.         return ((marriage_t *)last)->next == (marriage_t *)this;
  1103. }
  1104.  
  1105. /*(
  1106.  ********************************************************************************** 
  1107.  *
  1108.  *    Function:    move_tree
  1109.  *
  1110.  *
  1111.  *    Inputs:
  1112.  *        marriage - the base of the tree to move
  1113.  *        dx - the ammount by which to move the tree
  1114.  *
  1115.  *    Outputs:
  1116.  *        none.
  1117.  *
  1118.  *    Error Handling:
  1119.  *        none.
  1120.  *
  1121.  *    Description:
  1122.  *        
  1123.  * Moves the tree based at 'person' by an ammount 'dx' in the X direction. No
  1124.  * effect in the Y direction.
  1125.  * 
  1126.  ********************************************************************************** 
  1127. )*/
  1128.  
  1129. void move_tree(person_t *person, int dx)
  1130. {
  1131.     person_t *child;
  1132.     marriage_t *marriage;
  1133.  
  1134.     dbprintf(( "move_tree: move person %s %s by %d\n",
  1135.             person->firstname, person->family, dx));
  1136.  
  1137.     if (person->married)
  1138.     {
  1139.         marriage = person->firstmarriage;
  1140.         while(marriage)
  1141.         {
  1142.             marriage->h.xpos += dx;
  1143.     
  1144.             child = marriage->firstchild;
  1145.             while(child)
  1146.             {
  1147.                 move_tree(child, dx);
  1148.                 child = child->nextchild;
  1149.             }
  1150.             marriage = marriage->next;
  1151.         }
  1152.     }
  1153.     else
  1154.         person->h.xpos += dx;
  1155. }
  1156.  
  1157. void move_marriage(marriage_t *marriage, int dx)
  1158. {
  1159.     person_t *child;
  1160.  
  1161.     dbprintf(( "move_marriage: move by %d\n", dx));
  1162.  
  1163.     while(marriage)
  1164.     {
  1165.         marriage->h.xpos += dx;
  1166.  
  1167.         child = marriage->firstchild;
  1168.         while(child)
  1169.         {
  1170.             move_tree(child, dx);
  1171.             child = child->nextchild;
  1172.         }
  1173.         marriage = marriage->next;
  1174.     }
  1175.  
  1176. }
  1177. /*(
  1178.  ***********************************************************************************
  1179.  *
  1180.  *    Function:    findright_back
  1181.  *
  1182.  *
  1183.  *    Inputs:
  1184.  *        marriage - pointer to the marriage from which to look
  1185.  *        level - the desired level.
  1186.  *
  1187.  *    Outputs:
  1188.  *        person_t * - pointer to the person found, or NULL
  1189.  *
  1190.  *    Error Handling:
  1191.  *        in case of error, and particularly when marriage ptr. or
  1192.  *    the backlink is null, NULL is returned.
  1193.  *
  1194.  *    Description:
  1195.  *        
  1196.  * Searches for the next person at the desired level left from the current
  1197.  * marriage. This search may proceed back as far as is necessary (or possible).
  1198.  * This routine uses findright_forw to search forwards (younger) from given start
  1199.  * points.
  1200.  * 
  1201.  * The search uses the backlink which was constrcted when the initial layout was
  1202.  * done, as the mapping from child to parent is one-to-many so it cannot be
  1203.  * searched for.
  1204.  * 
  1205.  * The primary use for this routine is in the construction of the left/right links
  1206.  * which link up members of the same generation in order.
  1207.  * 
  1208.  ***********************************************************************************
  1209. )*/
  1210.  
  1211. static pmheader_t *findright_back(marriage_t *marriage, int level)
  1212. {
  1213.     pmheader_t *q;
  1214.     person_t *p;
  1215.     marriage_t *m, *mback;
  1216.  
  1217.     if (marriage == NULL)
  1218.     {
  1219.         dbprintf(("findright_back: no marriage!!.\n"));
  1220.         return NULL;
  1221.     }
  1222.     mback = marriage->backlink;
  1223.     if (mback == NULL)
  1224.     {
  1225.         dbprintf(("findright_back: no backlink.\n"));
  1226.         return NULL;
  1227.     }
  1228.     
  1229.     while(marriage)
  1230.     {
  1231.         m = marriage->backlink;
  1232.         
  1233.         dbprintf(("findright_back: look for person from %s (level %d) at level %d (backlink %spresent)\n",
  1234.                 nameof((pmheader_t*)marriage), marriage->h.level, level, m ? "" : "not "));
  1235.         
  1236.         if (m->lastchild != marriage->husband && m->lastchild != marriage->wife)
  1237.         {
  1238.             /*
  1239.              * marriage not first child - try some of the children.
  1240.              *
  1241.              * First find out which parent is the child of the marriage given.
  1242.              */
  1243.             p = m->firstchild;
  1244.             while(p != NULL && p != marriage->husband && p != marriage->wife)
  1245.             {
  1246.                 p = p->nextchild;
  1247.             }
  1248.  
  1249.             /*
  1250.              * p is should now point to the child of the older marriage who is
  1251.              * a parent in this one. (p == NULL) is an error.
  1252.              */
  1253.             p = p->nextchild;
  1254.             assert(p != NULL);
  1255.             while (p)
  1256.             {
  1257.                 dbprintf(("findright_back: examining child: %s\n", nameof((pmheader_t*)p)));
  1258.  
  1259.                 /*
  1260.                  * if the level's match, this is it!
  1261.                  */
  1262.                 if (p->h.level == level)
  1263.                 {
  1264.                     dbprintf(("findright_back: found %s %s at level %d\n",
  1265.                             p->firstname, p->family, p->h.level));
  1266.                     return mof((pmheader_t*)p, XP_FIRST);
  1267.                 }
  1268.  
  1269.                 /*
  1270.                  * levels didn't match. Try following this marriage...
  1271.                  * (p->h.level < level implies that we are too old still)
  1272.                  */
  1273.                 if (p->h.level < level && p->married)
  1274.                 {
  1275.                     q = findright_forw(p->firstmarriage, level);
  1276.                     if (q)
  1277.                     {
  1278.                         return q;
  1279.                     }
  1280.                 }
  1281. #ifdef DEBUG
  1282.                 else if (p->married)
  1283.                     dbprintf(("findright_back: child married, but level too high already to match.\n"));
  1284.                 else
  1285.                     dbprintf(("findright_back: child not married, cannot continue here.\n"));
  1286. #endif
  1287.                 p = p->nextchild;
  1288.             }
  1289.         }
  1290.  
  1291.         dbprintf(("findright_back: %snext marriage.\n", marriage->next ? "" : "no "));
  1292.  
  1293.         marriage = marriage->next;
  1294.     }
  1295.  
  1296.     dbprintf(("findright_back: calling findright_back lev %d to check previous links\n",level)); 
  1297.     
  1298.     q = findright_back(mback, level);
  1299.     return q;
  1300. }
  1301.  
  1302. /*(
  1303.  ***********************************************************************************
  1304.  *
  1305.  *    Function:    findright_forw
  1306.  *
  1307.  *
  1308.  *    Inputs:
  1309.  *        marriage - pointer to the marriage from which to look
  1310.  *        level - level which is being looked for.
  1311.  *
  1312.  *    Outputs:
  1313.  *        person_t * - pointer to person found, or NULL
  1314.  *
  1315.  *    Error Handling:
  1316.  *        
  1317.  *
  1318.  *    Description:
  1319.  *        
  1320.  * Finds the next person at the desired level. The match condition required that
  1321.  * the person found is the leftmost person possible from the given start position.
  1322.  * 
  1323.  ***********************************************************************************
  1324. )*/
  1325.  
  1326. static pmheader_t *findright_forw(marriage_t *marriage, int level)
  1327. {
  1328.     pmheader_t *r;
  1329.     person_t *p, *q;
  1330.     marriage_t *m;
  1331.  
  1332.     dbprintf(("findright_forw: look for person from %s / %s at level %d\n",
  1333.             marriage->husband->firstname, marriage->wife->firstname, level));
  1334.  
  1335.     /*
  1336.      * go back looking at each older child's tree to see if they  have 
  1337.      * a child at the appropriate level.
  1338.      */
  1339.     while(marriage)
  1340.     {
  1341.         p = marriage->firstchild;
  1342.         while(p)
  1343.         {
  1344.             if (p->h.level == level)
  1345.             {
  1346.                 dbprintf(("findright_forw: found %s %s at level %d\n",
  1347.                         p->firstname, p->family, p->h.level));
  1348.                 return mof((pmheader_t*)p, XP_FIRST);
  1349.             }
  1350.  
  1351.             if (p->married)
  1352.             {
  1353.                 /*
  1354.                  * look through the person's children (if any) & check.
  1355.                  * If any are married, recurse to check them too.
  1356.                  */
  1357.                 m = p->firstmarriage;
  1358.                 while(m)
  1359.                 {
  1360.                     q = m->firstchild;
  1361.                     while(q)
  1362.                     {
  1363.                         /*
  1364.                          * found it!
  1365.                          */
  1366.                         if (q->h.level == level)
  1367.                         {
  1368.                             dbprintf(("findright_forw: found %s %s at level %d\n",
  1369.                                     p->firstname, p->family, p->h.level));
  1370.                             return mof((pmheader_t*)q, XP_FIRST);
  1371.                         }
  1372.  
  1373.                         if (q->married)
  1374.                         {
  1375.                             r = findright_forw(q->firstmarriage, level);
  1376.                             if (r)
  1377.                             {
  1378.                                 return (pmheader_t*)r;
  1379.                             }
  1380.                         }
  1381.                         
  1382.                         q = q->nextchild;
  1383.                     }
  1384.                     m = m->next;
  1385.                 }
  1386.             }
  1387.             else
  1388.                 dbprintf(("findright_forw: %s not married & not correct level (%d) => not suitable.\n",
  1389.                             p->firstname, level));
  1390.  
  1391.             p = p->nextchild;
  1392.         }
  1393.         dbprintf(("findright_forw: %snext marriage.\n", marriage->next ? "" : "no "));
  1394.  
  1395.         marriage = marriage->next;
  1396.     }
  1397.  
  1398.     dbprintf(("findright_forw: nothing found.\n"));
  1399.     return NULL;
  1400. }
  1401.  
  1402. /*(
  1403.  ***********************************************************************************
  1404.  *
  1405.  *    Function:    xposof
  1406.  *
  1407.  *
  1408.  *    Inputs:
  1409.  *        p - person pointer. 
  1410.  *        spec - used to determine which marriage to use, if any.
  1411.  *
  1412.  *    Outputs:
  1413.  *        int - xpos value of a person/marriage
  1414.  *
  1415.  *    Description:
  1416.  *        
  1417.  * Returns the xpos value for person. If person not married this is just the xpos
  1418.  * of the person. For marriages, because a person may have more than one location,
  1419.  * 'spec' is used to determine which of the posssible marriages to return the
  1420.  * position of. Currently, only the first and last in the list are needed.
  1421.  * 
  1422.  ***********************************************************************************
  1423. )*/
  1424.  
  1425. int xposof(pmheader_t *p, enum xpspec_t spec)
  1426. {
  1427.     if (p)
  1428.     {
  1429.         switch(p->type)
  1430.         {
  1431.             case HT_PERSON:
  1432.                 if (((person_t*)p)->married)
  1433.                 {
  1434.                     if (spec == XP_FIRST)
  1435.                         return ((person_t*)p)->firstmarriage->h.xpos;
  1436.                     else
  1437.                         return ((person_t*)p)->lastmarriage->h.xpos;
  1438.                 }
  1439.                 else
  1440.                     return p->xpos;
  1441.  
  1442.             case HT_MARRIAGE:
  1443.                 return p->xpos;
  1444.         }
  1445.     }
  1446.     dbprintf(("WARNING: NULL pointer passed to xposof()\n"));
  1447.     return 0;
  1448. }
  1449.  
  1450. /*(
  1451.  ***********************************************************************************
  1452.  *
  1453.  *    Function:    pwidthof
  1454.  *
  1455.  *
  1456.  *    Inputs:
  1457.  *        p - person pointer. 
  1458.  *        spec - used to determine which marriage to use, if any.
  1459.  *
  1460.  *    Outputs:
  1461.  *        int - width of a person/marriage
  1462.  *
  1463.  *    Description:
  1464.  *        
  1465.  * Returns the width for person or marriage. If person not married this is just
  1466.  * the width of the person. For marriages, because a person may have more than one
  1467.  * marriage and hence width, 'spec' is used to determine which of the posssible
  1468.  * marriages to return the width of. Currently, only the first and last in the
  1469.  * list are needed.
  1470.  * 
  1471.  ***********************************************************************************
  1472. )*/
  1473.  
  1474. int pwidthof(pmheader_t *p, enum xpspec_t spec)
  1475. {
  1476.     if (p)
  1477.     {
  1478.         switch(p->type)
  1479.         {
  1480.             case HT_PERSON:
  1481.                 if (((person_t*)p)->married)
  1482.                 {
  1483.                     if (spec == XP_FIRST)
  1484.                         return ((person_t*)p)->firstmarriage->h.width;
  1485.                     else
  1486.                         return ((person_t*)p)->lastmarriage->h.width;
  1487.                 }
  1488.                 else
  1489.                     return p->width;
  1490.  
  1491.             case HT_MARRIAGE:
  1492.                 return p->width;
  1493.         }
  1494.     }
  1495.     dbprintf(("WARNING: NULL pointer passed to pwidthof()\n"));
  1496.     return 0;
  1497. }
  1498.  
  1499.  
  1500. /*(
  1501.  ***********************************************************************************
  1502.  *
  1503.  *    Function:    mof
  1504.  *
  1505.  *
  1506.  *    Inputs:
  1507.  *        p - person pointer. 
  1508.  *        spec - used to determine which marriage to use, if any.
  1509.  *
  1510.  *    Outputs:
  1511.  *        int - xpos value of a person/marriage
  1512.  *
  1513.  *    Description:
  1514.  *        
  1515.  * Returns the marriage header for person. If person not married this is simply
  1516.  * the header passed in. Because a person may have more than one marriage, 'spec'
  1517.  * is used to determine which of the posssible marriages to return the position
  1518.  * of. Currently, only the first and last in the list are needed.
  1519.  * 
  1520.  ***********************************************************************************
  1521. )*/
  1522.  
  1523. pmheader_t * mof(pmheader_t *p, enum xpspec_t spec)
  1524. {
  1525.     if (p)
  1526.     {
  1527.         switch(p->type)
  1528.         {
  1529.             case HT_PERSON:
  1530.                 if (((person_t*)p)->married)
  1531.                 {
  1532.                     if (spec == XP_FIRST)
  1533.                         return (pmheader_t*)((person_t*)p)->firstmarriage;
  1534.                     else
  1535.                         return (pmheader_t*)((person_t*)p)->lastmarriage;
  1536.                 }
  1537.                 else
  1538.                     return p;
  1539.  
  1540.             case HT_MARRIAGE:
  1541.                 return p;
  1542.         }
  1543.     }
  1544.     dbprintf(("WARNING: NULL pointer passed to mof()\n"));
  1545.     return NULL;
  1546. }
  1547.  
  1548. /*(
  1549.  ***********************************************************************************
  1550.  *
  1551.  *    Function:    normalise_area
  1552.  *
  1553.  *
  1554.  *    Inputs:
  1555.  *        opts - global options
  1556.  *        marriage - marriage root
  1557.  *
  1558.  *    Outputs:
  1559.  *        None.
  1560.  *
  1561.  *    Description:
  1562.  *        
  1563.  * Calls find_boundingbox to calculate the area used by the chart. It then forces
  1564.  * the chart's left egde to be visible on the first page printed by adding any
  1565.  * negative offset to the x coords of the chart's elements.
  1566.  * 
  1567.  ***********************************************************************************
  1568. )*/
  1569.  
  1570. static void normalise_area(options_t *opts, marriage_t *marriage)
  1571. {
  1572.     person_t *p;
  1573.     
  1574.     /*
  1575.      * find the bounding box for the diagram; this gets
  1576.      * used in the %%BoundingBox: DSC comment.
  1577.      */
  1578.     opts->bblx = 999;
  1579.     opts->bbly = 999;
  1580.     opts->bbux = -999;
  1581.     opts->bbuy = -999;
  1582.     find_boundingbox(opts, marriage);
  1583.     
  1584.     if (opts->bblx < 0)
  1585.     {
  1586.         int dx = - opts->bblx;
  1587.         
  1588.         while(marriage)
  1589.         {
  1590.             marriage->h.xpos += dx;
  1591.             p = marriage->firstchild;
  1592.             while(p)
  1593.             {
  1594.                 move_tree(p, dx);
  1595.                 p = p->nextchild;
  1596.             }
  1597.             marriage = marriage->next;
  1598.         }
  1599.         /*
  1600.          * shift bb coords to match.
  1601.          */
  1602.         opts->bblx += dx;
  1603.         opts->bbux += dx;
  1604.     }
  1605.     
  1606.     /*
  1607.      * account for title at the top (normally bbuy would be
  1608.      * a positive number).
  1609.      */
  1610.     opts->bbuy = 0;
  1611. }
  1612.  
  1613. /*(
  1614.  ********************************************************************************** 
  1615.  *
  1616.  *    Function:    findmarriage1
  1617.  *
  1618.  *
  1619.  *    Inputs:
  1620.  *        id - the ID to look for
  1621.  *
  1622.  *    Outputs:
  1623.  *        marriage_t * - pointer to a marriage struct or NULL
  1624.  *
  1625.  *    Error Handling:
  1626.  *        
  1627.  *
  1628.  *    Description:
  1629.  *        
  1630.  *    Finds the marriage in which one person has the ID code 'id'.
  1631.  *
  1632.  ********************************************************************************** 
  1633. )*/
  1634.  
  1635. marriage_t *findfirstmarriage(id_t id)
  1636. {
  1637.     marriage_t *m, *found;
  1638.  
  1639.     if (id == NOID)
  1640.     {
  1641.         dbprintf(( "findfirstmarriage: no id\n"));
  1642.         return NULL;
  1643.     }
  1644.     m = mroot;
  1645.     found = NULL;
  1646.     while(m)
  1647.     {
  1648.         if ( ((m->husband != NULL) && idcmp(id, m->husband->id) )    ||
  1649.              ((m->wife    != NULL) && idcmp(id, m->wife->id))    )
  1650.         {
  1651.             found = m;
  1652.             dbprintf(( "findfirstmarriage: found initial match for %lx\n", id));
  1653.         }
  1654.         m = m->nextmarriage;
  1655.     }
  1656.     
  1657.     if (found)
  1658.     {
  1659.         /*
  1660.          * go to the first marriage in this list
  1661.          */
  1662.         while(found->prev)
  1663.         {
  1664.             dbprintf(( "findfirstmarriage: found earlier match\n"));
  1665.             found = found->prev;
  1666.         }
  1667.     }
  1668.     else
  1669.         dbprintf(( "findfirstmarriage: no match found for %lx\n", id));
  1670.     
  1671.     return found;
  1672. }
  1673.  
  1674. /*(
  1675.  ********************************************************************************** 
  1676.  *
  1677.  *    Function:    findmarriage2
  1678.  *
  1679.  *
  1680.  *    Inputs:
  1681.  *        id - the ID to look for
  1682.  *
  1683.  *    Outputs:
  1684.  *        marriage_t * - pointer to a marriage struct or NULL
  1685.  *
  1686.  *    Error Handling:
  1687.  *        
  1688.  *
  1689.  *    Description:
  1690.  *        
  1691.  *        Finds the marriage in which one person has the ID code 'id'.
  1692.  *
  1693.  ********************************************************************************** 
  1694. )*/
  1695.  
  1696. marriage_t *findmarriage2(id_t hid, id_t wid)
  1697. {
  1698.     marriage_t *m;
  1699.  
  1700.     if (hid == NOID || wid == NOID)
  1701.     {
  1702.         dbprintf(( "findmarriage2: no id\n"));
  1703.         return NULL;
  1704.     }
  1705.     m = mroot;
  1706.     while(m)
  1707.     {
  1708.         if (((m->husband != NULL) && idcmp(hid, m->husband->id)) ||
  1709.             ((m->wife    != NULL) && idcmp(wid, m->wife->id)))
  1710.         {
  1711.             dbprintf(( "findmarriage2: found match h%lx/w%lx\n", hid, wid));
  1712.             break;
  1713.         }
  1714.         m = m->nextmarriage;
  1715.     }
  1716.     return m;
  1717. }
  1718.  
  1719.  
  1720. /*(
  1721.  ********************************************************************************** 
  1722.  *
  1723.  *    Function:    findperson
  1724.  *
  1725.  *
  1726.  *    Inputs:
  1727.  *        id - person id code
  1728.  *
  1729.  *    Outputs:
  1730.  *        person_t * - pointer to a person record
  1731.  *
  1732.  *    Error Handling:
  1733.  *        Checks that id is non-null. returns NULL if
  1734.  * person not found.
  1735.  *
  1736.  *    Description:
  1737.  *        
  1738.  *    Returns (a pointer to) the person record for the person who matches the
  1739.  * id code. 
  1740.  *
  1741.  ********************************************************************************** 
  1742. )*/
  1743.  
  1744. person_t *findperson(id_t id)
  1745. {
  1746.     person_t *p;
  1747.     p = proot;
  1748.  
  1749.     if (id == NULL)
  1750.     {
  1751.         dbprintf(( "findperson: no id\n"));
  1752.         return NULL;
  1753.     }
  1754.     while(p)
  1755.     {
  1756.         if (idcmp(id, p->id))
  1757.         {
  1758.             dbprintf(( "findperson: found match %lx\n", p->id));
  1759.             break;
  1760.         }
  1761.         p = p->nextperson;
  1762.     }
  1763.     return p;
  1764. }
  1765.  
  1766.  
  1767. /*(
  1768.  ********************************************************************************** 
  1769.  *
  1770.  *    Function:    show_generations
  1771.  *
  1772.  *
  1773.  *    Inputs:
  1774.  *        none.
  1775.  *
  1776.  *    Outputs:
  1777.  *        none.
  1778.  *
  1779.  *    Description:
  1780.  * 
  1781.  * Prints out the generations line-by-line, as they should appear on the plot but
  1782.  * in text form. Debugging aid only. Prints out both directions (should be the
  1783.  * same).
  1784.  * 
  1785.  ********************************************************************************** 
  1786. )*/
  1787.  
  1788. #ifdef DEBUG
  1789. static void show_generations()
  1790. {
  1791.     pmheader_t *p;
  1792.     int i;
  1793.     dbprintf(("show generations: %d levels; left->right\n", nlevels));
  1794.     for (i = 0; i < nlevels; i++)
  1795.     {
  1796.         p = generation[i].first;
  1797.         dbprintf(("%d: ", i));
  1798.         while(p)
  1799.         {
  1800.             switch(p->type)
  1801.             {
  1802.                 case HT_PERSON:
  1803.                     dbprintf(("%s", ((person_t*)p)->firstname));
  1804.                     break;
  1805.                 case HT_MARRIAGE:
  1806.                     dbprintf(("'%s / %s'", ((marriage_t*)p)->husband->firstname, ((marriage_t*)p)->wife->firstname));
  1807.                     break;
  1808.             }
  1809.             p = p->right;
  1810.             if (p)
  1811.                 dbprintf((" -> "));
  1812.         }
  1813.         dbprintf(("\n"));
  1814.     }
  1815.     dbprintf(("\nshow generations: %d levels; right->left\n", nlevels));
  1816.     for (i = 0; i < nlevels; i++)
  1817.     {
  1818.         p = generation[i].last;
  1819.         dbprintf(("%d: ", i));
  1820.         while(p)
  1821.         {
  1822.             switch(p->type)
  1823.             {
  1824.                 case HT_PERSON:
  1825.                     dbprintf(("%s", ((person_t*)p)->firstname));
  1826.                     break;
  1827.                 case HT_MARRIAGE:
  1828.                     dbprintf(("'%s & %s'", ((marriage_t*)p)->husband->firstname, ((marriage_t*)p)->wife->firstname));
  1829.                     break;
  1830.             }
  1831.             p = p->left;
  1832.             if (p)
  1833.                 dbprintf((" <- "));
  1834.         }
  1835.         dbprintf(("\n"));
  1836.     }
  1837. }
  1838.  
  1839. static char *nameof(pmheader_t *this)
  1840. {
  1841.     char buf[80];
  1842.  
  1843.     if (this)
  1844.     {
  1845.         switch(this->type)
  1846.         {
  1847.             case HT_PERSON:
  1848.                 sprintf(buf, "\"%s\"", ((person_t*)this)->firstname );
  1849.                 return strdup(buf);
  1850.  
  1851.             case HT_MARRIAGE:
  1852.                 sprintf(buf, "'%s & %s'", ((marriage_t*)this)->husband->firstname,
  1853.                         ((marriage_t*)this)->wife->firstname);
  1854.                 return strdup(buf);
  1855.  
  1856.             default:
  1857.                 return "unknown";
  1858.         }
  1859.     }
  1860.     else
  1861.         return "no-one";
  1862. }
  1863.  
  1864. #if CHECK_LINKS
  1865. #define check_p_b(p, s)        if (((long)(p) & 1) == 1) {dbprintf(("%s ptr error\n", s)); break;}
  1866. #define check_pers(p, s)    if ((p)->h.type != HT_PERSON) {dbprintf(("%s not a person\n", s)); break;}
  1867. #define check_marr(p, s)    if ((p)->h.type != HT_MARRIAGE) {dbprintf(("%s not a marriage\n", s)); break;}
  1868.  
  1869. void check_links()
  1870. {
  1871.     person_t *p;
  1872.     marriage_t *m;
  1873.  
  1874.     dbprintf(("check links ... "));
  1875.     m = mroot;
  1876.     while(m != NULL)
  1877.     {
  1878.         check_p_b(m, "m");
  1879.         check_marr(m, "m");
  1880.         check_p_b(m->h.left, "m->h.left");
  1881.         check_p_b(m->h.right, "m->h.right");
  1882.         check_p_b(m->nextmarriage, "m->nextmarriage");
  1883.         check_p_b(m->next, "m->next");
  1884.         check_p_b(m->prev, "m->prev");
  1885.         check_p_b(m->husband, "m->husband");
  1886.         check_p_b(m->wife, "m->wife");
  1887.         check_p_b(m->backlink, "m->backlink");
  1888.         check_p_b(m->firstchild, "m->firstchild");
  1889.         check_p_b(m->lastchild, "m->lastchild");
  1890.         
  1891.         check_pers(m->wife, "m->wife");
  1892.         check_pers(m->husband, "m->husband");
  1893.         if (m->backlink != NULL)
  1894.             check_marr(m->backlink, "m->backlink");
  1895.         
  1896.         m = m->nextmarriage;
  1897.     }
  1898.     dbprintf((" people ... \n"));
  1899.     p = proot;
  1900.     while(p != NULL)
  1901.     {
  1902.         check_p_b(p, "p");
  1903.         check_pers(p, "p");
  1904.         check_p_b(p->h.left, "p->h.left");
  1905.         check_p_b(p->h.right, "p->h.right");
  1906.         check_p_b(p->nextperson, "p->nextperson");
  1907.         check_p_b(p->parents, "p->parents");
  1908.         check_p_b(p->nextchild, "p->nextchild");
  1909.         check_p_b(p->lastchild, "p->lastchild");
  1910.         check_p_b(p->firstmarriage, "p->firstmarriage");
  1911.         check_p_b(p->lastmarriage, "p->lastmarriage");
  1912.         
  1913.         if (p->nextchild)
  1914.             check_pers(p->nextchild, "p->nextchild");
  1915.         if (p->lastchild)
  1916.             check_pers(p->lastchild, "p->lastchild");
  1917.         
  1918.         if (p->parents)
  1919.             check_marr(p->parents, "p->parents");
  1920.         if (p->firstmarriage)
  1921.             check_marr(p->firstmarriage, "p->firstmarriage");
  1922.         if (p->lastmarriage)
  1923.             check_marr(p->lastmarriage, "p->lastmarriage");
  1924.         
  1925.         p = p->nextperson;
  1926.     }
  1927.     dbprintf(("done\n"));
  1928. }
  1929. #endif
  1930. #endif
  1931. @
  1932.  
  1933.  
  1934. 1.8
  1935. log
  1936. @Fixed up the code to deal correctly with multiple marriages.
  1937. Added a number of debugging statements and removed some of
  1938. the redundant code - set_left_links etc. replacing them with
  1939. the mirror_right_links code. As a result, findleft_back()
  1940. and findleft_forw() can go too.
  1941. Major changes result from the fact that some pointers can now
  1942. point at marriage_t's or person_t's.
  1943. Finally, added a routine check_links to check that the pointer
  1944. referenced are valid and, where possible to check, correct. This
  1945. is conditional on CHECK_LINKS being defined, and is not currently
  1946. called.
  1947. @
  1948. text
  1949. @d7 1
  1950. a7 1
  1951.  *    $Date: 1994/03/26 11:28:03 $
  1952. d11 1
  1953. a11 1
  1954.  *    $Revision: 1.7 $
  1955. d16 13
  1956. d173 1
  1957. a173 2
  1958.     generation[0].first = (pmheader_t*)findperson(opts->startperson);
  1959.     generation[0].last = generation[0].first;
  1960. d291 2
  1961. d369 1
  1962. a369 1
  1963.                     child->lastmarriage->h.right = NULL;
  1964. a572 1
  1965.                 dbprintf(("%s, ", nameof(next)));
  1966. @
  1967.  
  1968.  
  1969. 1.7
  1970. log
  1971. @Included multiple-marriage support.
  1972. @
  1973. text
  1974. @d7 1
  1975. a7 1
  1976.  *    $Date: 1994/03/10 21:28:26 $
  1977. d11 1
  1978. a11 1
  1979.  *    $Revision: 1.6 $
  1980. d16 3
  1981. d41 1
  1982. d56 2
  1983. a57 5
  1984. static person_t *findleft_back(marriage_t *marriage, int level);
  1985. static person_t *findleft_forw(marriage_t *marriage, int level);
  1986. static person_t *findright_back(marriage_t *marriage, int level);
  1987. static person_t *findright_forw(marriage_t *marriage, int level);
  1988. static void set_left_links(options_t *, marriage_t *, int);
  1989. d62 18
  1990. a79 1
  1991. static void check_parents(person_t *person);
  1992. d82 1
  1993. a82 1
  1994.  ************************************************************* 
  1995. d98 11
  1996. a108 12
  1997.  *        Calls the routines to format and output PostScript
  1998.  * statements which will draw the family tree described in the
  1999.  * opts array, using data from the mroot/proot lists.
  2000.  *
  2001.  *         The tree is assumed to be a true tree - i.e. one root
  2002.  * node branching out to n leaf nodes. 
  2003.  *
  2004.  *         If the named 'outputfile' is 'con' this is taken as
  2005.  * a signal to write output to the standard output stream
  2006.  * instead of opening a new file.
  2007.  *
  2008.  ************************************************************* 
  2009. d117 1
  2010. a117 1
  2011.     if (strcmp(opts->outputfile, "con"))
  2012. d160 1
  2013. a160 1
  2014.     generation[0].first = findperson(opts->startperson);
  2015. a162 1
  2016.     set_left_links(opts, startmarriage, 1);
  2017. d164 5
  2018. d170 6
  2019. d181 8
  2020. a188 1
  2021.     adjust_layout(outf, opts);
  2022. d219 1
  2023. d238 1
  2024. a238 1
  2025.  ************************************************************* 
  2026. d256 7
  2027. a262 8
  2028.  *        Determines the initial placement of the marriage(s)
  2029.  * connected to 'id' and those marriages made by their children.
  2030.  * This initial placement ignores issues of overlap; this is dealt
  2031.  * with later. The main element here is the general x placement,
  2032.  * calculation of y placement, and the setting up of various
  2033.  * values in the person_t and marriage_t structures.
  2034.  *
  2035.  ************************************************************* 
  2036. d269 1
  2037. a269 1
  2038.     person_t *child, *lastchild;
  2039. d272 1
  2040. a272 1
  2041.     dbprintf(( "\ndo_simple_layout: do layout at: %d,%d level: %d\n", x,y, level));
  2042. d276 4
  2043. a279 8
  2044.         dbprintf(( "do_simple_layout: set marriage @@ %d x %d.\n", x, y));
  2045.         marriage->xpos = x;
  2046.         marriage->ypos = y;
  2047.         /* already done?:
  2048.          * if (marriage->width == 0)
  2049.          *    marriage->width = widthofmarriage(opts, marriage);
  2050.          */
  2051.         assert(marriage->width != 0);
  2052. a287 1
  2053.         lastchild = NULL;
  2054. d291 7
  2055. a297 2
  2056.             child->firstmarriage = findfirstmarriage(child->id);
  2057.             m = child->firstmarriage;
  2058. d300 3
  2059. d304 5
  2060. a308 5
  2061.                 dbprintf(("do_simple_layout: setting backlink for child marriage %s & %s to marriage %s & %s\n",
  2062.                         child->firstmarriage->husband->firstname, child->firstmarriage->wife->firstname,
  2063.                         marriage->husband->firstname, marriage->wife->firstname));
  2064.                 /* already done?: m->width = widthofmarriage(opts, m); */
  2065.                 ptwidth += m->width;
  2066. d317 10
  2067. a326 5
  2068.             child->married = (child->firstmarriage != NULL);
  2069.             child->fullname = !streq(child->family, marriage->husband->family) ||
  2070.                     child->married;
  2071.             child->width = widthof(opts, child);
  2072.             child->level = level + 1;
  2073. d328 1
  2074. d330 1
  2075. a330 1
  2076.              * set up the level pointers.
  2077. d332 6
  2078. a337 2
  2079.             child->right = child->nextchild;
  2080.             child->left = lastchild;
  2081. d339 19
  2082. a357 1
  2083.             ptwidth += child->width;
  2084. a358 2
  2085.             dbprintf(( "do_simple_layout: adding width for child %d\n", children));
  2086.             lastchild = child;
  2087. d361 1
  2088. d363 1
  2089. a363 1
  2090.         marriage->level = level;
  2091. d370 4
  2092. a373 2
  2093.             ptwidth -= (pwidthof(marriage->firstchild, XP_FIRST) + pwidthof(marriage->lastchild, XP_FIRST)) / 2;
  2094.  
  2095. d401 3
  2096. a403 4
  2097.                 child->xpos = startx;
  2098.                 child->ypos = childy;
  2099.                 dbprintf(( "do_simple_layout: child %s @@ %dx%d\n",
  2100.                                 child->firstname, startx, childy));
  2101. d409 2
  2102. a410 2
  2103.                         m->xpos = startx;
  2104.                         m->ypos = childy;
  2105. d412 1
  2106. a412 1
  2107.                             startx += (m->width + m->next->width) / 2;
  2108. d414 2
  2109. a415 1
  2110.                             startx += (m->width + pwidthof(child->nextchild, XP_FIRST)) / 2;
  2111. d417 2
  2112. a418 3
  2113.                         dbprintf(( "do_simple_layout:   marriage %s / %s @@ %dx%d, next: %d\n",
  2114.                                 m->husband->firstname, m->wife->firstname,
  2115.                                 m->xpos, m->ypos, startx));
  2116. d423 2
  2117. a424 1
  2118.                     startx += (child->width + pwidthof(child->nextchild, XP_FIRST)) / 2;
  2119. d439 1
  2120. a439 1
  2121.                             child->xpos, child->ypos, level+1);
  2122. d446 3
  2123. a449 1
  2124.         x += INCH;
  2125. d456 1
  2126. a456 1
  2127.  ***********************************************************************
  2128. d471 5
  2129. a475 5
  2130.  *        Modifies the data structure by adding in the left and
  2131.  * right pointers for inter-marriage links. Assumes that do_simple_layout
  2132.  * has already been done.
  2133.  *
  2134.  ***********************************************************************
  2135. d480 1
  2136. a481 1
  2137.     marriage_t *savemarriage = marriage;
  2138. d485 1
  2139. a485 1
  2140.     while(marriage)
  2141. d487 2
  2142. a488 3
  2143.         dbprintf(( "do_layout_part2: found marriage.\n"));
  2144.  
  2145.         if (marriage->children > 0)
  2146. d490 1
  2147. a490 2
  2148.             child = marriage->firstchild;
  2149.             while(child != NULL)
  2150. d492 1
  2151. a492 5
  2152.                 if (child->married)
  2153.                 {
  2154.                     do_layout_part2(opts, child->firstmarriage, level+1);
  2155.                 }
  2156.                 child = child->nextchild;
  2157. d494 1
  2158. a495 3
  2159.         dbprintf(( "do_layout_part2: finished marriage.\n"));
  2160.  
  2161.         marriage = marriage->next;
  2162. d502 1
  2163. a502 5
  2164.     marriage = savemarriage;
  2165.     while(marriage)
  2166.     {
  2167.         dbprintf(( "do_layout_part2: filling links for marriage %s & %s.\n",
  2168.                 marriage->husband->firstname,marriage->wife->firstname));
  2169. d504 2
  2170. a505 14
  2171.         child = findleft_back(marriage, level + 1);
  2172.         dbprintf(("do_layout_part2: findleft lev %d returns %s, firstchild: %s\n",
  2173.                 level+1, child ? child->firstname : "nothing",
  2174.                 marriage->firstchild ? marriage->firstchild->firstname : "nothing"));
  2175.  
  2176.         if (marriage->firstchild)
  2177.             marriage->firstchild->left = child;
  2178.  
  2179.         child = findright_back(marriage, level + 1);
  2180.         dbprintf(("do_layout_part2: findright lev %d returns %s, lastchild: %s\n",
  2181.                 level+1, child ? child->firstname : "nothing",
  2182.                 marriage->lastchild ? marriage->lastchild->firstname : "nothing"));
  2183.         if (marriage->lastchild)
  2184.             marriage->lastchild->right = child;
  2185. d507 1
  2186. a507 1
  2187.         dbprintf(( "do_layout_part2: finished links for marriage\n"));
  2188. d509 6
  2189. a514 4
  2190.         marriage = marriage->next;
  2191.     }
  2192.  
  2193.     dbprintf(( "do_layout_part2: finished level %d layout.\n", level));
  2194. d518 1
  2195. a518 1
  2196.  ***********************************************************************
  2197. d520 1
  2198. a520 1
  2199.  *    Function:    find_boundingbox
  2200. d524 1
  2201. a524 3
  2202.  *        opts - global options structure
  2203.  *        id - id code identifying the initial point
  2204.  *        level - generation/recursion level
  2205. d531 2
  2206. a532 1
  2207.  *        
  2208. d534 1
  2209. a534 1
  2210.  ***********************************************************************
  2211. d537 6
  2212. a542 2
  2213. #define set_low(var, val)    {if ((var) > (val)) (var) = (val); }
  2214. #define set_high(var, val)    {if ((var) < (val)) (var) = (val); }
  2215. d544 5
  2216. a548 4
  2217. static void find_boundingbox(options_t *opts, marriage_t *marriage)
  2218. {
  2219.     person_t *p;
  2220.     while (marriage)
  2221. d550 1
  2222. a550 3
  2223.         dbprintf(("find_boundingbox: marriage %s & %s: ",
  2224.                 marriage->husband->firstname,
  2225.                 marriage->wife->firstname));
  2226. d552 3
  2227. a554 6
  2228.         set_low(opts->bbly, marriage->ypos);
  2229.         set_high(opts->bbuy, marriage->ypos);
  2230.         set_low(opts->bblx, marriage->xpos - marriage->width / 2);
  2231.         set_high(opts->bbux, marriage->xpos + marriage->width / 2);
  2232.         
  2233.         if (marriage->children > 0)
  2234. d556 1
  2235. a556 3
  2236.             dbprintf(("child %s\n", marriage->firstchild->firstname));
  2237.             p = marriage->firstchild;
  2238.             while(p)
  2239. d558 4
  2240. a561 12
  2241.                 if (p->married)
  2242.                 {
  2243.                     find_boundingbox(opts, p->firstmarriage);
  2244.                 }
  2245.                 else
  2246.                 {
  2247.                     set_low(opts->bbly, p->ypos);
  2248.                     set_high(opts->bbuy, p->ypos);
  2249.                     set_low(opts->bblx, p->xpos - p->width / 2);
  2250.                     set_high(opts->bbux, p->xpos + p->width / 2);
  2251.                 }
  2252.                 p = p->nextchild;
  2253. d563 1
  2254. a564 4
  2255.         else
  2256.             dbprintf(("no children\n"));
  2257.         
  2258.         marriage = marriage->next;
  2259. d566 2
  2260. d571 1
  2261. a571 1
  2262.  ***********************************************************************
  2263. d573 1
  2264. a573 1
  2265.  *    Function:    set_left_links
  2266. a584 4
  2267.  *        
  2268.  *        Sets up generation[] array by scanning through the tree
  2269.  * looking for leftmost people on a level which hasn't been defined yet.
  2270.  * When found, the left pointer in the array is set to this person.
  2271. d586 9
  2272. a594 1
  2273.  ***********************************************************************
  2274. d597 4
  2275. a600 1
  2276. static void set_left_links(options_t *opts, marriage_t *marriage, int level)
  2277. a602 4
  2278.     
  2279.     if (marriage == NULL)
  2280.         return;
  2281.     
  2282. d605 6
  2283. a610 4
  2284.         dbprintf(("set_left_links: marriage %s & %s level %d: ",
  2285.                 marriage->husband->firstname,
  2286.                 marriage->wife->firstname,
  2287.                 level));
  2288. a611 13
  2289.         /*
  2290.          * operate the generation array on a first-come-first-served
  2291.          * basis, so we get the end points. We actually scan the whole
  2292.          * tree, though.
  2293.          */
  2294.         if (generation[level].first == NULL)
  2295.         {
  2296.             generation[level].first = marriage->firstchild;
  2297.             dbprintf(("FIRST: "));
  2298.         }
  2299.         if (nlevels < level)
  2300.             nlevels = level;
  2301.  
  2302. d614 1
  2303. a614 3
  2304.             dbprintf(("child %s (lev: %d)\n",
  2305.                     marriage->firstchild->firstname,
  2306.                     marriage->firstchild->level));
  2307. d620 8
  2308. a627 1
  2309.                     set_left_links(opts, p->firstmarriage, level+1);
  2310. d634 1
  2311. a634 1
  2312.     
  2313. d638 2
  2314. d642 1
  2315. a642 1
  2316.  ***********************************************************************
  2317. d657 5
  2318. a661 5
  2319.  *        Sets up generation[] array by scanning through the tree
  2320.  * looking for rightmost people on a level which hasn't been defined yet.
  2321.  * When found, the right pointer in the array is set to this person.
  2322.  *
  2323.  ***********************************************************************
  2324. a670 6
  2325.     /*
  2326.      * make sure we're at the end of this list of marriages.
  2327.      */
  2328.     while(marriage->next != NULL)
  2329.         marriage = marriage->next;
  2330.     
  2331. d673 1
  2332. a673 3
  2333.         dbprintf(("set_right_links: marriage %s & %s level %d: ",
  2334.                 marriage->husband->firstname, marriage->wife->firstname,
  2335.                 level));
  2336. d680 1
  2337. a680 1
  2338.         if (generation[level].last == NULL)
  2339. d682 2
  2340. a683 2
  2341.             generation[level].last = marriage->lastchild;
  2342.             dbprintf(("LAST: "));
  2343. d685 2
  2344. a686 2
  2345.         if (nlevels < level)
  2346.             nlevels = level;
  2347. d691 3
  2348. a693 3
  2349.                     marriage->firstchild->firstname,
  2350.                     marriage->firstchild->level));
  2351.             p = marriage->lastchild;
  2352. d698 1
  2353. a698 1
  2354.                     set_right_links(opts, p->lastmarriage, level+1);
  2355. d700 1
  2356. a700 1
  2357.                 p = p->lastchild;
  2358. d706 1
  2359. a706 1
  2360.         marriage = marriage->prev;
  2361. d711 1
  2362. a711 1
  2363.  ************************************************************* 
  2364. d718 2
  2365. a719 2
  2366.  *        id - the ID of the person to start at, who should be
  2367.  *            married.
  2368. d729 2
  2369. a730 3
  2370.  *        This routine takes the initial positions assigned by
  2371.  * the routine do_simple_layout and adjusts the positions such that
  2372.  * people do not overlap.
  2373. d732 12
  2374. a743 1
  2375.  ************************************************************* 
  2376. d746 5
  2377. a750 1
  2378. void adjust_layout(FILE *outf, options_t *opts)
  2379. d752 1
  2380. a752 1
  2381.     int c, gen, dx, moved;
  2382. d754 5
  2383. a758 1
  2384.     person_t *person, *lastperson;
  2385. d762 1
  2386. a762 1
  2387.     c = 0;
  2388. d766 1
  2389. a766 1
  2390.         for(gen = 0; gen <= nlevels; gen++)
  2391. d768 3
  2392. a770 5
  2393.             person = generation[gen].first;
  2394.             lastperson = NULL;
  2395.             dbprintf(("adjust_layout: generation %d (starts with %s %s, right %s)\n",
  2396.                         gen, person->firstname, person->family,
  2397.                         person->right ? person->right->firstname : "no-one"));
  2398. d772 1
  2399. a772 1
  2400.             while(person)
  2401. d774 1
  2402. a774 1
  2403.                 if (lastperson != NULL)
  2404. d776 2
  2405. d783 7
  2406. a789 2
  2407.                     dx = (xposof(person, XP_FIRST) - xposof(lastperson, XP_LAST));
  2408.                     dx -= ((pwidthof(person, XP_FIRST) + pwidthof(lastperson, XP_LAST) ) / 2 );
  2409. d791 2
  2410. a792 3
  2411.                     dbprintf(("examining %s & %s (%d vs %d), dx = %d\n",
  2412.                         lastperson->firstname, person->firstname,
  2413.                         xposof(lastperson, XP_LAST), xposof(person, XP_FIRST), dx));
  2414. a802 1
  2415.  
  2416. d805 2
  2417. a806 2
  2418.                         p2 = person;
  2419.                         while(p2)
  2420. d808 15
  2421. a822 2
  2422.                             move_tree(p2, dx);
  2423.                             p2 = p2->nextchild;
  2424. a823 1
  2425.                         move_parents = TRUE;
  2426. d825 1
  2427. a825 1
  2428.                     else if (dx > 1 && lastperson->nextchild == person)
  2429. d831 1
  2430. a831 1
  2431.                         if (lastperson->lastchild == NULL && !lastperson->married)
  2432. d834 2
  2433. a835 2
  2434.                                 lastperson->firstname, person->firstname, dx));
  2435.                             lastperson->xpos += dx;
  2436. d840 1
  2437. a840 1
  2438.                         if (person->nextchild == NULL && !person->married)
  2439. d843 2
  2440. a844 2
  2441.                                 person->firstname, lastperson->firstname, dx));
  2442.                             person->xpos -= dx;
  2443. d851 1
  2444. a851 1
  2445.                     if (lastperson->nextchild == person)
  2446. d857 1
  2447. a857 1
  2448.                         if (person->nextchild != NULL && !person->married)
  2449. d862 3
  2450. a864 3
  2451.                             nc = person->nextchild;
  2452.                             dx2 = xposof(nc, XP_FIRST) - person->xpos;
  2453.                             dx2 -= ((person->width + pwidthof(nc, XP_FIRST)) / 2 );
  2454. d867 1
  2455. a867 1
  2456.                                 lastperson->firstname, dx, person->firstname, dx2, nc->firstname, diff / 2));
  2457. d871 2
  2458. a872 2
  2459.                                     person->firstname, diff / 2));
  2460.                                 person->xpos += diff / 2;
  2461. d879 2
  2462. a880 2
  2463.                                     person->firstname, diff / 2));
  2464.                                 person->xpos += diff / 2;
  2465. a884 5
  2466.                         else
  2467.                         {
  2468.                             dbprintf(("adjust_layout: cannot centre %s %s\n",
  2469.                                     person->firstname, person->family));
  2470.                         }
  2471. d888 1
  2472. a888 4
  2473.                         if (person->parents)
  2474.                         {
  2475.                             check_parents(person);
  2476.                         }
  2477. d893 2
  2478. a894 2
  2479.                 lastperson = person;
  2480.                 person = person->right;
  2481. d901 7
  2482. a907 5
  2483.         c++;
  2484.         /* print_tree(outf, opts, findfirstmarriage(opts,opts->startperson)); */
  2485.         /* fprintf(outf, "showpage\n"); */
  2486.     } while(moved && c < MAX_ADJUSTS);
  2487.     if (c == MAX_ADJUSTS) 
  2488. d911 1
  2489. a911 1
  2490.     fprintf(stderr, "adjust_layout: took %d tries to adjust layout.\n", c);
  2491. d913 4
  2492. d919 28
  2493. a946 1
  2494. static void check_parents(person_t *person)
  2495. d949 12
  2496. a960 1
  2497.     marriage_t *m = person->parents;
  2498. d964 3
  2499. a966 16
  2500.         dbprintf(("check_parents: checking marriage %s / %s\n",
  2501.                     m->husband->firstname, m->wife->firstname));
  2502.         /*
  2503.          * get range of X used by children of this marriage...
  2504.          */
  2505.         fc = xposof(m->lastchild, XP_FIRST);
  2506.         lc = xposof(m->firstchild, XP_FIRST);
  2507.         dxp = fc - lc;
  2508.         if (dxp < 0)
  2509.             dxp = - dxp;
  2510.         xp = fc + (dxp / 2);
  2511.         
  2512.         /*
  2513.          * and check that the marriage is decently centred.
  2514.          */
  2515.         if (abs(xp - m->xpos) > 1)
  2516. d968 19
  2517. a986 5
  2518.             dbprintf(("check_parents: child %s of parents @@ %d / %d\n",
  2519.                     person->firstname, fc, lc));
  2520.             dbprintf(("check_parents: moving parents %s & %s by %d to %d\n",
  2521.                     m->husband->firstname, m->wife->firstname, xp - m->xpos, xp));
  2522.             m->xpos = xp;
  2523. d992 32
  2524. d1026 1
  2525. a1026 1
  2526.  ************************************************************* 
  2527. d1043 4
  2528. a1046 4
  2529.  *        Moves the tree based at 'marriage' by an ammount 'dx'
  2530.  * in the X direction. No effect in the Y direction.
  2531.  *
  2532.  ************************************************************* 
  2533. d1062 1
  2534. a1062 1
  2535.             marriage->xpos += dx;
  2536. d1074 1
  2537. a1074 2
  2538.         person->xpos += dx;
  2539.  
  2540. d1077 3
  2541. a1079 20
  2542. /*(
  2543.  ************************************************************* 
  2544.  *
  2545.  *    Function:    widthof
  2546.  *
  2547.  *
  2548.  *    Inputs:
  2549.  *        opts - global options
  2550.  *        pers - pointer to a person record.
  2551.  *
  2552.  *    Outputs:
  2553.  *        int -width in PS units (points) of the printed
  2554.  *            version of the person.
  2555.  *
  2556.  *    Description:
  2557.  *        
  2558.  *        return the width required to print 'person'
  2559.  *
  2560.  ************************************************************* 
  2561. )*/
  2562. d1081 1
  2563. a1081 4
  2564. int widthof(options_t *opts, person_t *pers)
  2565. {
  2566.     int w, namew, datew;
  2567.     char bufn[128], bufd[128];
  2568. d1083 1
  2569. a1083 1
  2570.     if (pers->fullname)
  2571. d1085 9
  2572. a1093 3
  2573.         strcpy(bufn, pers->firstname);
  2574.         strcat(bufn, " ");
  2575.         strcat(bufn, pers->family);
  2576. a1094 14
  2577.     else
  2578.         strcpy(bufn, pers->firstname);
  2579.     
  2580.     namew = (int)stringwidth(&opts->personfont, opts->afmconst, bufn);
  2581.  
  2582.     datefmt(bufd, &pers->born, &pers->died);
  2583.     datew = (int)stringwidth(&opts->datefont, opts->afmconst, bufd);
  2584.  
  2585.     dbprintf(("widthof: person %s / %s returns %d / %d\n", bufn, bufd, namew, datew));
  2586.  
  2587.     if (namew > datew)
  2588.         w = namew + opts->tree_gap;
  2589.     else    
  2590.         w = datew + opts->tree_gap;
  2591. a1095 4
  2592.     dbprintf(( "widthof: %s width of \"%s\" is \t%d.\n", 
  2593.         (pers->fullname)?"full":"short", pers->firstname, w));
  2594.  
  2595.     return w;
  2596. a1096 22
  2597.  
  2598. int widthofmarriage(options_t *opts, marriage_t *marriage)
  2599. {
  2600.     int w1, w2, w3;
  2601.     
  2602.     w1 = widthof(opts, marriage->husband);
  2603.     w2 = widthof(opts, marriage->wife);
  2604.     
  2605.     w3 = (int)stringwidth(&opts->symfont, opts->afmconst, "x");
  2606.     if (marriage->when.known)
  2607.          w3 += (int)stringwidth(&opts->datefont, opts->afmconst, date2string(&marriage->when));
  2608.     
  2609.     if (w1 < w2)
  2610.         w1 = w2;
  2611.     if (w1 < w3)
  2612.         w1 = w3;
  2613.     
  2614.     dbprintf(("widthofmarriage: return %d for marriage width\n", w1));
  2615.     
  2616.     return w1;
  2617. }
  2618.  
  2619. d1098 1
  2620. a1098 1
  2621.  ***********************************************************************
  2622. d1100 1
  2623. a1100 1
  2624.  *    Function:    findleft_back
  2625. d1116 13
  2626. a1128 14
  2627.  *        Searches for the next person at the desired level left
  2628.  * from the current marriage. This search may proceed back as far as is
  2629.  * necessary (or possible). This routine uses findleft_forw to search
  2630.  * forwards (younger) from given start points.
  2631.  *
  2632.  *        The search uses the backlink which was constrcted when
  2633.  * the initial layout was done, as the mapping from child to parent is
  2634.  * one-to-many so it cannot be searched for.
  2635.  *
  2636.  *        The primary use for this routine is in the construction
  2637.  * of the left/right links which link up members of the same generation
  2638.  * in order.
  2639.  *
  2640.  ***********************************************************************
  2641. d1131 1
  2642. a1131 1
  2643. static person_t *findleft_back(marriage_t *marriage, int level)
  2644. d1133 3
  2645. a1135 6
  2646.     person_t *p, *q;
  2647.     marriage_t *m;
  2648.  
  2649.     dbprintf(("findleft_back: look for marriage from %s / %s at level %d (backlink %s)\n",
  2650.             marriage->husband->firstname, marriage->wife->firstname, level,
  2651.             marriage->backlink ? "present" : "not present"));
  2652. d1139 1
  2653. a1139 1
  2654.         dbprintf(("findleft_back: no marriage!!.\n"));
  2655. d1142 2
  2656. a1143 1
  2657.     if (marriage->backlink == NULL)
  2658. d1145 1
  2659. a1145 1
  2660.         dbprintf(("findleft_back: no backlink.\n"));
  2661. d1149 1
  2662. a1149 2
  2663.     m = marriage->backlink;
  2664.     if (m->firstchild != marriage->husband && m->firstchild != marriage->wife)
  2665. d1151 6
  2666. a1156 16
  2667.         /*
  2668.          * marriage not first child - try some of the children.
  2669.          *
  2670.          * First find out which parent is the child of the marriage given.
  2671.          */
  2672.         p = m->firstchild;
  2673.         while(p != NULL && p != marriage->husband && p != marriage->wife)
  2674.         {
  2675.             p = p->nextchild;
  2676.         }
  2677.  
  2678.         /*
  2679.          * p is should now point to the child of the older marriage who is
  2680.          * a parent in this one. (p == NULL) is an error.
  2681.          */
  2682.         while((p = p->lastchild))
  2683. a1157 1
  2684.  
  2685. d1159 3
  2686. a1161 1
  2687.              * if the level's match, this is it!
  2688. d1163 2
  2689. a1164 1
  2690.             if (p->level == level)
  2691. d1166 1
  2692. a1166 3
  2693.                 dbprintf(("findleft_back: found %s %s at level %d\n",
  2694.                         p->firstname, p->family, p->level));
  2695.                 return p;
  2696. d1170 2
  2697. a1171 2
  2698.              * levels didn't match. Try following this marriage...
  2699.              * (p->level < level implies that we are too old still)
  2700. d1173 3
  2701. a1175 1
  2702.             if (p->level < level && p->married)
  2703. d1177 31
  2704. a1207 3
  2705.                 q = findleft_forw(p->firstmarriage, level);
  2706.                 if (q)
  2707.                     return q;
  2708. d1210 4
  2709. d1216 4
  2710. a1219 1
  2711.     return findleft_back(m, level);
  2712. d1223 1
  2713. a1223 1
  2714.  ***********************************************************************
  2715. d1225 1
  2716. a1225 1
  2717.  *    Function:    findleft_forw
  2718. d1240 4
  2719. a1243 5
  2720.  *        Finds the next person at the desired level. The match 
  2721.  * condition required that the person found is the leftmost person possible
  2722.  * from the given start position.
  2723.  *
  2724.  ***********************************************************************
  2725. d1246 1
  2726. a1246 1
  2727. static person_t *findleft_forw(marriage_t *marriage, int level)
  2728. d1248 2
  2729. a1249 1
  2730.     person_t *p, *q, *r;
  2731. d1252 1
  2732. a1252 1
  2733.     dbprintf(("findleft_forw: look for marriage from %s / %s at level %d\n",
  2734. d1259 1
  2735. a1259 2
  2736.     p = marriage->lastchild;
  2737.     while(p)
  2738. d1261 2
  2739. a1262 1
  2740.         if (p->level == level)
  2741. d1264 6
  2742. a1269 4
  2743.             dbprintf(("findleft_forw: found %s %s at level %d\n",
  2744.                     p->firstname, p->family, p->level));
  2745.             return p;
  2746.         }
  2747. d1271 1
  2748. a1271 10
  2749.         if (p->married)
  2750.         {
  2751.             /*
  2752.              * look backwards through the person's children
  2753.              * (if any) & check. If any are married, recurse to
  2754.              * check them too.
  2755.              */
  2756.             m = p->firstmarriage;
  2757.             q = m->lastchild;
  2758.             while(q)
  2759. d1274 2
  2760. a1275 1
  2761.                  * found!
  2762. d1277 2
  2763. a1278 1
  2764.                 if (q->level == level)
  2765. d1280 12
  2766. a1291 4
  2767.                     dbprintf(("findleft_forw: found %s %s at level %d\n",
  2768.                             p->firstname, p->family, p->level));
  2769.                     return q;
  2770.                 }
  2771. d1293 10
  2772. a1302 7
  2773.                 if (q->married)
  2774.                 {
  2775.                     r = findleft_forw(q->firstmarriage, level);
  2776.                     if (r)
  2777.                     {
  2778.                         dbprintf(("findleft_forw: already found, returning...\n"));
  2779.                         return r;
  2780. d1304 1
  2781. a1305 2
  2782.                 
  2783.                 q = q->lastchild;
  2784. d1307 3
  2785. a1309 34
  2786.         }
  2787.         p = p->lastchild;
  2788.     }
  2789.  
  2790.     dbprintf(("findleft_forw: nothing found.\n"));
  2791.     return NULL;
  2792. }
  2793.  
  2794. /*(
  2795.  ***********************************************************************
  2796.  *
  2797.  *    Function:    
  2798.  *
  2799.  *
  2800.  *    Inputs:
  2801.  *        
  2802.  *
  2803.  *    Outputs:
  2804.  *        
  2805.  *
  2806.  *    Error Handling:
  2807.  *        
  2808.  *
  2809.  *    Description:
  2810.  *        
  2811.  *        
  2812.  *
  2813.  ***********************************************************************
  2814. )*/
  2815.  
  2816. static person_t *findright_back(marriage_t *marriage, int level)
  2817. {
  2818.     person_t *p, *q;
  2819.     marriage_t *m;
  2820. a1310 26
  2821.     dbprintf(("findright_back: look for marriage from %s / %s at level %d (backlink %s)\n",
  2822.             marriage->husband->firstname, marriage->wife->firstname, level,
  2823.             marriage->backlink ? "present" : "not present"));
  2824.  
  2825.     if (marriage == NULL)
  2826.     {
  2827.         dbprintf(("findright_back: no marriage!!.\n"));
  2828.         return NULL;
  2829.     }
  2830.     if (marriage->backlink == NULL)
  2831.     {
  2832.         dbprintf(("findright_back: no backlink.\n"));
  2833.         return NULL;
  2834.     }
  2835.     
  2836.     m = marriage->backlink;
  2837.     if (m->lastchild != marriage->husband && m->lastchild != marriage->wife)
  2838.     {
  2839.         /*
  2840.          * marriage not first child - try some of the children.
  2841.          *
  2842.          * First find out which parent is the child of the marriage given.
  2843.          */
  2844.         p = m->firstchild;
  2845.         while(p != NULL && p != marriage->husband && p != marriage->wife)
  2846.         {
  2847. d1313 1
  2848. d1315 1
  2849. a1315 28
  2850.         /*
  2851.          * p is should now point to the child of the older marriage who is
  2852.          * a parent in this one. (p == NULL) is an error.
  2853.          */
  2854.         while((p = p->nextchild))
  2855.         {
  2856.  
  2857.             /*
  2858.              * if the level's match, this is it!
  2859.              */
  2860.             if (p->level == level)
  2861.             {
  2862.                 dbprintf(("findright_back: found %s %s at level %d\n",
  2863.                         p->firstname, p->family, p->level));
  2864.                 return p;
  2865.             }
  2866.  
  2867.             /*
  2868.              * levels didn't match. Try following this marriage...
  2869.              * (p->level < level implies that we are too old still)
  2870.              */
  2871.             if (p->level < level && p->married)
  2872.             {
  2873.                 q = findright_forw(p->firstmarriage, level);
  2874.                 if (q)
  2875.                     return q;
  2876.             }
  2877.         }
  2878. d1318 2
  2879. a1319 1
  2880.     return findright_back(m, level);
  2881. d1323 1
  2882. a1323 1
  2883.  ***********************************************************************
  2884. d1325 1
  2885. a1325 1
  2886.  *    Function:    
  2887. d1329 2
  2888. a1330 1
  2889.  *        
  2890. d1333 1
  2891. a1333 4
  2892.  *        
  2893.  *
  2894.  *    Error Handling:
  2895.  *        
  2896. d1337 6
  2897. a1342 3
  2898.  *        
  2899.  *
  2900.  ***********************************************************************
  2901. d1345 1
  2902. a1345 2
  2903.  
  2904. static person_t *findright_forw(marriage_t *marriage, int level)
  2905. d1347 1
  2906. a1347 14
  2907.     person_t *p, *q, *r;
  2908.     marriage_t *m;
  2909.  
  2910.     dbprintf(("findright_forw: look for marriage from %s / %s at level %d\n",
  2911.             marriage->husband->firstname, marriage->wife->firstname, level));
  2912.  
  2913.     if (marriage == NULL)
  2914.     {
  2915.         dbprintf(("findright_forw: no marriage!!.\n"));
  2916.         return NULL;
  2917.     }
  2918.     
  2919.     p = marriage->firstchild;
  2920.     while(p)
  2921. d1349 1
  2922. a1349 8
  2923.         if (p->level == level)
  2924.         {
  2925.             dbprintf(("findright_forw: found %s %s at level %d\n",
  2926.                     p->firstname, p->family, p->level));
  2927.             return p;
  2928.         }
  2929.  
  2930.         if (p->married)
  2931. d1351 2
  2932. a1352 13
  2933.             /*
  2934.              * look backwards through the person's children
  2935.              * (if any) & check. If any are married, recurse to
  2936.              * check them too.
  2937.              */
  2938.             m = p->firstmarriage;
  2939.             q = m->firstchild;
  2940.             while(q)
  2941.             {
  2942.                 /*
  2943.                  * found!
  2944.                  */
  2945.                 if (q->level == level)
  2946. d1354 4
  2947. a1357 3
  2948.                     dbprintf(("findright_forw: found %s %s at level %d\n",
  2949.                             p->firstname, p->family, p->level));
  2950.                     return q;
  2951. d1359 2
  2952. d1362 2
  2953. a1363 12
  2954.                 if (q->married)
  2955.                 {
  2956.                     r = findright_forw(q->firstmarriage, level);
  2957.                     if (r)
  2958.                     {
  2959.                         dbprintf(("findright_forw: already found, returning...\n"));
  2960.                         return r;
  2961.                     }
  2962.                 }
  2963.                 
  2964.                 q = q->nextchild;
  2965.             }
  2966. a1364 1
  2967.         p = p->nextchild;
  2968. d1366 2
  2969. a1367 3
  2970.  
  2971.     dbprintf(("findright_forw: nothing found.\n"));
  2972.     return NULL;
  2973. d1371 1
  2974. a1371 1
  2975.  ***********************************************************************
  2976. d1373 1
  2977. a1373 1
  2978.  *    Function:    xposof
  2979. d1381 1
  2980. a1381 1
  2981.  *        int - xpos value of a person/marriage
  2982. d1385 7
  2983. a1391 7
  2984.  *        Returns the xpos value for person. If person not married this is
  2985.  * just the xpos of the person. For marriages, because a person may have
  2986.  * more than one location, 'spec' is used to determine which of the
  2987.  * posssible marriages to return the position of. Currently, only the first
  2988.  * and last in the list are needed.
  2989.  *
  2990.  ***********************************************************************
  2991. d1394 1
  2992. a1394 1
  2993. int xposof(person_t *p, enum xpspec_t spec)
  2994. d1398 1
  2995. a1398 1
  2996.         if (p->married)
  2997. d1400 13
  2998. a1412 4
  2999.             if (spec == XP_FIRST)
  3000.                 return p->firstmarriage->xpos;
  3001.             else
  3002.                 return p->lastmarriage->xpos;
  3003. a1413 2
  3004.         else
  3005.             return p->xpos;
  3006. d1415 1
  3007. d1419 1
  3008. d1421 1
  3009. a1421 1
  3010.  ***********************************************************************
  3011. d1423 1
  3012. a1423 1
  3013.  *    Function:    pwidthof
  3014. d1435 6
  3015. a1440 7
  3016.  *        Returns the xpos value for person. If person not married this is
  3017.  * just the xpos of the person. For marriages, because a person may have
  3018.  * more than one location, 'spec' is used to determine which of the
  3019.  * posssible marriages to return the position of. Currently, only the first
  3020.  * and last in the list are needed.
  3021.  *
  3022.  ***********************************************************************
  3023. d1443 1
  3024. a1443 1
  3025. int pwidthof(person_t *p, enum xpspec_t spec)
  3026. d1447 1
  3027. a1447 1
  3028.         if (p->married)
  3029. d1449 13
  3030. a1461 4
  3031.             if (spec == XP_FIRST)
  3032.                 return p->firstmarriage->width;
  3033.             else
  3034.                 return p->lastmarriage->width;
  3035. a1462 2
  3036.         else
  3037.             return p->width;
  3038. d1464 2
  3039. a1465 1
  3040.     return 0;
  3041. d1469 1
  3042. a1469 1
  3043.  ***********************************************************************
  3044. d1479 1
  3045. a1479 4
  3046.  *        
  3047.  *
  3048.  *    Error Handling:
  3049.  *        
  3050. d1483 5
  3051. a1487 6
  3052.  *        Calls find_boundingbox to calculate the area used by the
  3053.  * chart. It then forces the chart's left egde to be visible on the first
  3054.  * page printed by adding any negative offset to the x coords of the
  3055.  * chart's elements.
  3056.  *
  3057.  ***********************************************************************
  3058. d1510 1
  3059. a1510 1
  3060.             marriage->xpos += dx;
  3061. d1534 1
  3062. a1534 1
  3063.  ************************************************************* 
  3064. d1550 1
  3065. a1550 2
  3066.  *        Finds the marriage in which one person has the
  3067.  * ID code 'id'.
  3068. d1552 1
  3069. a1552 1
  3070.  ************************************************************* 
  3071. d1572 1
  3072. a1572 1
  3073.             dbprintf(( "findfirstmarriage: found initial match %lx\n", id));
  3074. d1588 2
  3075. d1595 1
  3076. a1595 1
  3077.  ************************************************************* 
  3078. d1611 1
  3079. a1611 2
  3080.  *        Finds the marriage in which one person has the
  3081.  * ID code 'id'.
  3082. d1613 1
  3083. a1613 1
  3084.  ************************************************************* 
  3085. d1639 1
  3086. d1641 1
  3087. a1641 1
  3088.  ************************************************************* 
  3089. d1658 2
  3090. a1659 2
  3091.  *        Returns (a pointer to) the person record for
  3092.  * the person who matches the id code. 
  3093. d1661 1
  3094. a1661 1
  3095.  ************************************************************* 
  3096. d1686 165
  3097. @
  3098.  
  3099.  
  3100. 1.6
  3101. log
  3102. @Multiple pages working!
  3103. @
  3104. text
  3105. @d7 1
  3106. a7 1
  3107.  *    $Date: 1994/03/07 13:00:31 $
  3108. d11 1
  3109. a11 1
  3110.  *    $Revision: 1.5 $
  3111. d16 3
  3112. d41 2
  3113. d46 4
  3114. d56 3
  3115. a58 3
  3116. static void set_left_links(options_t *, id_t, int);
  3117. static void set_right_links(options_t *, id_t, int);
  3118. static void do_layout_part2(options_t *opts, id_t id, int level);
  3119. d60 2
  3120. a61 1
  3121. static void normalise_area(options_t *opts);
  3122. d97 2
  3123. a98 1
  3124.     int i;
  3125. d112 6
  3126. d119 1
  3127. a119 1
  3128.         generation[i].first = generation[i].last = 0;
  3129. a120 2
  3130.     dbprintf(("\n----------------------------------- do_prolog ------------------------------------------------------\n"));
  3131.  
  3132. d122 1
  3133. d126 1
  3134. a126 2
  3135.     do_simple_layout(opts, opts->startperson, (opts->pagewidth - opts->rmargin)/2,
  3136.              opts->titlefont.linespc + 3*opts->personfont.linespc, 0);
  3137. d130 6
  3138. a135 1
  3139.     do_layout_part2(opts, opts->startperson, 0);
  3140. d143 5
  3141. a147 2
  3142.     set_left_links(opts, opts->startperson, 0);
  3143.     set_right_links(opts, opts->startperson, 0);
  3144. d154 1
  3145. a154 1
  3146.     adjust_layout(outf, opts, opts->startperson);
  3147. d159 3
  3148. a161 1
  3149.      * get the bounding box for PS.
  3150. d163 1
  3151. a163 1
  3152.     normalise_area(opts);
  3153. d165 2
  3154. d168 1
  3155. a168 1
  3156.      * print out the prolog stuff
  3157. d177 1
  3158. a177 1
  3159.     do_title(outf, opts);
  3160. d184 1
  3161. a184 1
  3162.     print_tree(outf, opts, opts->startperson);
  3163. d198 2
  3164. d231 1
  3165. a231 1
  3166. void do_simple_layout(options_t *opts, id_t id, int x, int y, int level)
  3167. d236 1
  3168. a236 1
  3169.     marriage_t *marriage;
  3170. d238 1
  3171. a238 1
  3172.     dbprintf(( "\ndo_simple_layout: do layout for ID %lx at: %d,%d level: %d\n", id, x,y, level));
  3173. a239 1
  3174.     marriage = findmarriage1(id);
  3175. d242 1
  3176. a242 1
  3177.         dbprintf(( "do_simple_layout: found marriage.\n"));
  3178. d245 5
  3179. d252 2
  3180. a253 1
  3181.          * work out how many children there are
  3182. d262 3
  3183. a264 2
  3184.             child->firstmarriage = findmarriage1(child->id);
  3185.             if (child->firstmarriage)
  3186. d266 1
  3187. a266 1
  3188.                 child->firstmarriage->backlink = marriage;
  3189. d268 11
  3190. a278 4
  3191.                         child->firstmarriage->husband->firstname,
  3192.                         child->firstmarriage->wife->firstname,
  3193.                         marriage->husband->firstname,
  3194.                         marriage->wife->firstname));
  3195. d306 1
  3196. a306 1
  3197.             ptwidth -= (marriage->firstchild->width + marriage->lastchild->width) / 2;
  3198. d330 1
  3199. a330 1
  3200.              * have a go at placing the children.
  3201. d339 20
  3202. a358 1
  3203.                 startx += (child->width + child->nextchild->width) / 2;
  3204. d370 1
  3205. a370 1
  3206.                      * these positions should be 'plain'
  3207. d372 2
  3208. a373 2
  3209.                     do_simple_layout(opts, child->id,
  3210.                         child->xpos, child->ypos, level+1);
  3211. d384 1
  3212. a384 1
  3213.     dbprintf(( "do_simple_layout: finished simple layout for ID %lx.\n", id));
  3214. d410 1
  3215. a410 1
  3216. static void do_layout_part2(options_t *opts, id_t id, int level)
  3217. d413 1
  3218. a413 1
  3219.     marriage_t *marriage;
  3220. d415 1
  3221. a415 1
  3222.     dbprintf(( "\ndo_layout_part2: ID: %lx, level %d\n", id, level));
  3223. a416 1
  3224.     marriage = findmarriage1(id);
  3225. d428 1
  3226. a428 1
  3227.                     do_layout_part2(opts, child->id, level+1);
  3228. d442 1
  3229. a442 1
  3230.     marriage = findmarriage1(id);
  3231. d448 3
  3232. a450 3
  3233.         child = findleftat(marriage, level + 1);
  3234.         dbprintf(("do_layout_part2: findleft lev %d returns %s, firstchild: %s\n", level+1,
  3235.                 child ? child->firstname : "nothing",
  3236. d456 3
  3237. a458 3
  3238.         child = findrightat(marriage, level + 1);
  3239.         dbprintf(("do_layout_part2: findright lev %d returns %s, lastchild: %s\n", level+1,
  3240.                 child ? child->firstname : "nothing",
  3241. d463 1
  3242. a463 1
  3243.         dbprintf(( "do_layout_part2: finished links for marriage %lx.\n", id));
  3244. d468 1
  3245. a468 1
  3246.     dbprintf(( "do_layout_part2: finished simple layout for ID %lx.\n", id));
  3247. d498 1
  3248. a498 1
  3249.     if (marriage)
  3250. d531 2
  3251. d559 1
  3252. a559 1
  3253. static void set_left_links(options_t *opts, id_t id, int level)
  3254. d562 3
  3255. a564 1
  3256.     marriage_t *marriage;
  3257. d566 1
  3258. a566 2
  3259.     marriage = findmarriage1(id);
  3260.     if (marriage)
  3261. d579 1
  3262. d581 2
  3263. d596 1
  3264. a596 2
  3265.                     set_left_links(opts, p->id, level+1);
  3266.                     break;
  3267. d603 2
  3268. d611 1
  3269. a611 1
  3270.  *    Function:    set_left_links
  3271. d625 1
  3272. a625 1
  3273.  * looking for leftmost people on a level which hasn't been defined yet.
  3274. d631 1
  3275. a631 1
  3276. static void set_right_links(options_t *opts, id_t id, int level)
  3277. d634 9
  3278. a642 1
  3279.     marriage_t *marriage;
  3280. d644 1
  3281. a644 2
  3282.     marriage = findmarriage1(id);
  3283.     if (marriage)
  3284. d647 1
  3285. a647 2
  3286.                 marriage->husband->firstname,
  3287.                 marriage->wife->firstname,
  3288. d656 1
  3289. d658 2
  3290. d673 1
  3291. a673 2
  3292.                     set_right_links(opts, p->id, level+1);
  3293.                     break;
  3294. d680 2
  3295. d711 1
  3296. a711 1
  3297. void adjust_layout(FILE *outf, options_t *opts, id_t id)
  3298. d713 1
  3299. a713 1
  3300.     int c, i, dx, moved;
  3301. d723 1
  3302. a723 1
  3303.         for(i = 0; i <= nlevels; i++)
  3304. d725 1
  3305. a725 1
  3306.             person = generation[i].first;
  3307. d727 2
  3308. a728 2
  3309.             dbprintf(("adjust_layout: generation %d (starts with %s %s, right %s)\n", i,
  3310.                         person->firstname, person->family,
  3311. d740 2
  3312. a741 2
  3313.                     dx = (xposof(person) - xposof(lastperson));
  3314.                     dx -= ((lastperson->width + person->width) / 2 );
  3315. d745 1
  3316. a745 1
  3317.                         xposof(lastperson), xposof(person), dx));
  3318. d805 2
  3319. a806 2
  3320.                             dx2 = xposof(nc) - xposof(person);
  3321.                             dx2 -= ((person->width + nc->width) / 2 );
  3322. d837 1
  3323. a837 10
  3324.                             int dxp, xp;
  3325.                             marriage_t *m = person->parents;
  3326.                             dxp = xposof(m->lastchild) - xposof(m->firstchild);
  3327.                             if (dxp < 0)
  3328.                                 dxp = - dxp;
  3329.                             xp = xposof(m->firstchild) + (dxp / 2);
  3330.                             dbprintf(("adjust_layout: moved child %s so moving parents %s & %s by %d to %d\n",
  3331.                                     person->firstname,person->parents->husband->firstname,
  3332.                                     person->parents->wife->firstname, xp - m->xpos, xp));
  3333.                             m->xpos = xp;
  3334. d852 1
  3335. a852 1
  3336.         /* print_tree(outf, opts, opts->startperson); */
  3337. d863 35
  3338. d933 1
  3339. a933 4
  3340.         marriage->xpos += dx;
  3341.  
  3342.         child = marriage->firstchild;
  3343.         while(child)
  3344. d935 9
  3345. a943 2
  3346.             move_tree(child, dx);
  3347.             child = child->nextchild;
  3348. d958 2
  3349. a959 1
  3350.  *        
  3351. d962 2
  3352. a963 4
  3353.  *        
  3354.  *
  3355.  *    Error Handling:
  3356.  *        
  3357. d974 2
  3358. a975 3
  3359.     int w;
  3360.     int l, ld;
  3361.     char *s;
  3362. d979 3
  3363. a981 2
  3364.         l = strlen(pers->family);
  3365.         l += strlen(pers->firstname) + 1;
  3366. d984 30
  3367. a1013 3
  3368.     {
  3369.         l = strlen(pers->firstname);
  3370.     }
  3371. d1015 4
  3372. a1018 10
  3373.     /*
  3374.      * account for the date - see functions in print.c for
  3375.      * date formatting. generally:
  3376.      *    (<born> - <died>) where <born> & <died> are like
  3377.      *  27-May-74 or blank
  3378.      */
  3379.     s = date2string(&pers->born);
  3380.     ld = strlen(s);
  3381.     s = date2string(&pers->died);
  3382.     ld += strlen(s) + 5;
  3383. d1020 1
  3384. a1020 5
  3385.     if (ld > l)
  3386.     {
  3387.         dbprintf(( "widthof: date %d longer than name %d, using date len.\n", ld, l));
  3388.         l = ld;
  3389.     }
  3390. d1022 1
  3391. a1022 6
  3392.     w = (opts->personfont.size * l) * opts->afmconst;
  3393.     w = w + opts->tree_gap;
  3394.  
  3395.     dbprintf(( "widthof: %s width of \"%s\" is \t%d (%dc).\n", 
  3396.         (pers->fullname)?"full":"short", pers->firstname, w, l));
  3397.     return w;
  3398. d1028 1
  3399. a1028 1
  3400.  *    Function:    
  3401. d1032 2
  3402. a1033 1
  3403.  *        
  3404. d1036 1
  3405. a1036 1
  3406.  *        
  3407. d1039 2
  3408. a1040 1
  3409.  *        
  3410. d1044 12
  3411. a1055 1
  3412.  *        
  3413. a1059 5
  3414. person_t *findleftat(marriage_t *marriage, int level)
  3415. {
  3416.     return findleft_back(marriage, level);
  3417. }
  3418.  
  3419. d1130 1
  3420. a1130 1
  3421.  *    Function:    
  3422. d1134 2
  3423. a1135 1
  3424.  *        
  3425. d1138 1
  3426. a1138 1
  3427.  *        
  3428. d1145 3
  3429. a1147 1
  3430.  *        
  3431. a1236 5
  3432. person_t *findrightat(marriage_t *marriage, int level)
  3433. {
  3434.     return findright_back(marriage, level);
  3435. }
  3436.  
  3437. d1395 1
  3438. a1395 1
  3439.  *    Function:    
  3440. d1399 2
  3441. a1400 1
  3442.  *        
  3443. d1403 1
  3444. a1403 4
  3445.  *        
  3446.  *
  3447.  *    Error Handling:
  3448.  *        
  3449. d1407 5
  3450. a1411 1
  3451.  *        
  3452. d1416 1
  3453. a1416 1
  3454. int xposof(person_t *p)
  3455. d1421 6
  3456. a1426 1
  3457.             return p->firstmarriage->xpos;
  3458. d1436 1
  3459. a1436 1
  3460.  *    Function:    
  3461. d1440 2
  3462. a1441 1
  3463.  *        
  3464. d1444 1
  3465. a1444 1
  3466.  *        
  3467. a1445 3
  3468.  *    Error Handling:
  3469.  *        
  3470.  *
  3471. d1448 5
  3472. a1452 1
  3473.  *        
  3474. d1457 1
  3475. a1457 1
  3476. int yposof(person_t *p)
  3477. d1462 6
  3478. a1467 1
  3479.             return p->firstmarriage->ypos;
  3480. d1469 1
  3481. a1469 1
  3482.             return p->ypos;
  3483. d1477 1
  3484. a1477 1
  3485.  *    Function:    
  3486. d1481 2
  3487. a1482 1
  3488.  *        
  3489. d1492 4
  3490. a1495 1
  3491.  *        
  3492. d1500 1
  3493. a1500 1
  3494. static void normalise_area(options_t *opts)
  3495. a1501 1
  3496.     marriage_t *m = findmarriage1(opts->startperson);
  3497. d1512 1
  3498. a1512 1
  3499.     find_boundingbox(opts, m);
  3500. d1518 1
  3501. a1518 3
  3502.         m->xpos += dx;
  3503.         p = m->firstchild;
  3504.         while(p)
  3505. d1520 8
  3506. a1527 2
  3507.             move_tree(p, dx);
  3508.             p = p->nextchild;
  3509. d1537 2
  3510. a1538 1
  3511.      * account for title at the top.
  3512. d1542 153
  3513. @
  3514.  
  3515.  
  3516. 1.5
  3517. log
  3518. @Reduced stringwidth const.
  3519. @
  3520. text
  3521. @d7 1
  3522. a7 1
  3523.  *    $Date: 1994/03/07 12:44:14 $
  3524. d11 1
  3525. a11 1
  3526.  *    $Revision: 1.4 $
  3527. d16 3
  3528. d41 1
  3529. a41 2
  3530. #define TREE_GAP    10
  3531. #define MAX_ADJUSTS    20
  3532. a105 12
  3533.     /*
  3534.      * print out the prolog stuff
  3535.      */
  3536.     do_prolog(outf, opts);
  3537.     
  3538.     dbprintf(("\n----------------------------------- do_title -------------------------------------------------------\n"));
  3539.  
  3540.     /*
  3541.      * put a title on the page
  3542.      */
  3543.     do_title(outf, opts);
  3544.     
  3545. d140 12
  3546. d637 1
  3547. d688 1
  3548. a688 13
  3549.                         if (person->parents)
  3550.                         {
  3551.                             int dxp, xp;
  3552.                             marriage_t *m = person->parents;
  3553.                             dxp = xposof(m->lastchild) - xposof(m->firstchild);
  3554.                             if (dxp < 0)
  3555.                                 dxp = - dxp;
  3556.                             xp = xposof(m->firstchild) + (dxp / 2);
  3557.                             dbprintf(("adjust_layout: moved child %s so moving parents %s & %s by %d to %d\n",
  3558.                                     person->firstname,person->parents->husband->firstname,
  3559.                                     person->parents->wife->firstname, xp - m->xpos, xp));
  3560.                             m->xpos = xp;
  3561.                         }
  3562. d690 1
  3563. a690 1
  3564.                     else if (dx > TREE_GAP && lastperson->nextchild == person)
  3565. d703 1
  3566. d712 1
  3567. d715 2
  3568. a716 2
  3569. #if 0
  3570.                     else if (lastperson->nextchild == person)
  3571. d725 1
  3572. a725 1
  3573.                             int dx2, dx3;
  3574. d730 4
  3575. a733 3
  3576.                             dx3 = dx2 - dx;
  3577.                             dbprintf(("adjust_layout: check centering: dx2: %d, dx3: %d\n", dx2, dx3));
  3578.                             if (dx3 > TREE_GAP)
  3579. d736 2
  3580. a737 2
  3581.                                     person->firstname, dx3 / 2));
  3582.                                 person->xpos += dx3 / 2;
  3583. d741 1
  3584. a741 1
  3585.                             else if (dx3 < -TREE_GAP)
  3586. d744 2
  3587. a745 2
  3588.                                     person->firstname, dx3 / 2));
  3589.                                 person->xpos += dx3 / 2;
  3590. d750 22
  3591. a772 1
  3592. #endif
  3593. d791 1
  3594. d894 2
  3595. d897 1
  3596. d899 2
  3597. a900 2
  3598.     w = (opts->personfont.size * l) / 1.48;
  3599.     w = w + TREE_GAP;
  3600. d907 21
  3601. d1001 21
  3602. d1086 21
  3603. d1180 22
  3604. d1268 21
  3605. d1302 21
  3606. d1336 21
  3607. @
  3608.  
  3609.  
  3610. 1.4
  3611. log
  3612. @Passed on as first Version.
  3613. @
  3614. text
  3615. @d7 1
  3616. a7 1
  3617.  *    $Date: 1994/03/01 23:23:01 $
  3618. d11 1
  3619. a11 1
  3620.  *    $Revision: 1.3 $
  3621. d16 3
  3622. d880 1
  3623. a880 1
  3624.     w = (opts->personfont.size * l) / 1.6;
  3625. @
  3626.  
  3627.  
  3628. 1.3
  3629. log
  3630. @changes to complete layered adjustment of position
  3631. including auto-centering of parents.
  3632. @
  3633. text
  3634. @d7 1
  3635. a7 1
  3636.  *    $Date: 1994/02/27 19:32:55 $
  3637. d11 1
  3638. a11 1
  3639.  *    $Revision: 1.2 $
  3640. d16 4
  3641. d36 1
  3642. d45 2
  3643. d140 7
  3644. d409 63
  3645. a685 1
  3646.  
  3647. a689 1
  3648.  
  3649. a692 1
  3650.  
  3651. a693 2
  3652.                             /* m->husband->xpos = xp; */
  3653.                             /* m->wife->xpos = xp; */
  3654. a694 1
  3655.                         
  3656. d719 1
  3657. d754 1
  3658. d768 2
  3659. a769 2
  3660.     } while(moved && c < 10);
  3661.     if (c == 10) 
  3662. d850 2
  3663. a851 1
  3664.     int l;
  3665. d856 1
  3666. a856 1
  3667.         l += strlen(pers->firstname);
  3668. d862 16
  3669. a877 2
  3670.  
  3671.     w = (opts->personfont.size * l) / 1.5;
  3672. d1187 39
  3673. @
  3674.  
  3675.  
  3676. 1.2
  3677. log
  3678. @fixed layout problems of previous versions.
  3679. @
  3680. text
  3681. @d7 1
  3682. a7 1
  3683.  *    $Date: 1994/02/17 23:50:21 $
  3684. d11 1
  3685. a11 1
  3686.  *    $Revision: 1.1 $
  3687. d16 3
  3688. d31 1
  3689. a31 1
  3690. #define TREE_GAP    12
  3691. d75 1
  3692. d89 3
  3693. d131 1
  3694. a131 1
  3695.     adjust_layout(opts, opts->startperson);
  3696. d289 5
  3697. a293 2
  3698.                     do_simple_layout(opts, child->id, child->xpos,
  3699.                             child->ypos + opts->ticklen+1, level+1);
  3700. d300 1
  3701. a300 2
  3702.         /* marriage = nextmarriage(marriage, id); */
  3703.         marriage = NULL;
  3704. d307 23
  3705. d332 1
  3706. a332 3
  3707.     int children;
  3708.     int ptwidth, startx, childy;
  3709.     person_t *child, *lastchild;
  3710. d335 1
  3711. a335 1
  3712.     dbprintf(( "\ndo_simple_layout: do layout part 2: ID: %lx, level %d\n", id, level));
  3713. d356 1
  3714. a356 2
  3715.         /* marriage = nextmarriage(marriage, id); */
  3716.         marriage = NULL;
  3717. d386 1
  3718. a386 2
  3719.         /* marriage = nextmarriage(marriage, id); */
  3720.         marriage = NULL;
  3721. a388 1
  3722.  
  3723. d392 23
  3724. d423 12
  3725. a434 4
  3726.         dbprintf(("set_left_links: marriage %s & %s level %d: child %s (lev: %d)\n",
  3727.                 marriage->husband->firstname, marriage->wife->firstname,
  3728.                 level, marriage->firstchild->firstname, marriage->firstchild->level));
  3729.         generation[level].first = marriage->firstchild;
  3730. d440 3
  3731. d454 2
  3732. d459 23
  3733. d490 12
  3734. a501 4
  3735.         dbprintf(("set_right_links: marriage %s & %s level %d: child %s\n",
  3736.                 marriage->husband->firstname, marriage->wife->firstname,
  3737.                 level, marriage->firstchild->firstname));
  3738.         generation[level].last = marriage->lastchild;
  3739. d507 3
  3740. d521 2
  3741. d546 2
  3742. a547 2
  3743.  * the routine do_simple_layout and adjusts the positions
  3744.  * such that people do not overlap.
  3745. d552 1
  3746. a552 1
  3747. void adjust_layout(options_t *opts, id_t id)
  3748. d554 1
  3749. a554 1
  3750.     int i, dx, moved;
  3751. d559 1
  3752. d575 6
  3753. a580 1
  3754.                     dx = (person->xpos - lastperson->xpos);
  3755. d585 1
  3756. a585 1
  3757.                         lastperson->xpos, person->xpos, dx));
  3758. d587 1
  3759. a587 1
  3760.                     if (dx < 0)
  3761. d598 1
  3762. d607 9
  3763. a615 1
  3764.                             dbprintf(("adjust_layout: moved child %s so moving parents %s & %s by %d\n",
  3765. d617 1
  3766. a617 1
  3767.                                     person->parents->wife->firstname, dx));
  3768. d619 3
  3769. a621 3
  3770.                             person->parents->xpos += dx;
  3771.                             person->parents->husband->xpos = person->parents->xpos;
  3772.                             person->parents->wife->xpos = person->parents->xpos;
  3773. d625 57
  3774. d692 8
  3775. a699 1
  3776.     } while(moved);
  3777. a734 2
  3778.     person->xpos += dx;
  3779.  
  3780. d747 3
  3781. d841 1
  3782. a841 1
  3783.         while(p = p->lastchild)
  3784. d876 1
  3785. a876 1
  3786.     dbprintf(("findleft_forw: look for marriage from %s / %s at level %d (backlink %s)\n",
  3787. d978 1
  3788. a978 1
  3789.         while(p = p->nextchild)
  3790. d1073 25
  3791. @
  3792.  
  3793.  
  3794. 1.1
  3795. log
  3796. @Initial revision
  3797. @
  3798. text
  3799. @d3 1
  3800. a3 1
  3801.  *     $RCSfile$
  3802. d5 1
  3803. a5 1
  3804.  *    $Author$
  3805. d7 1
  3806. a7 1
  3807.  *    $Date$
  3808. d9 1
  3809. a9 1
  3810.  *    $State$
  3811. d11 1
  3812. a11 1
  3813.  *    $Revision$
  3814. d15 3
  3815. a17 1
  3816.  *    $Log$
  3817. d19 1
  3818. d30 7
  3819. a36 1
  3820. int people_moved;
  3821. a71 2
  3822.     person_t *pers;
  3823.     marriage_t *marr;;
  3824. d85 2
  3825. d92 2
  3826. d99 1
  3827. d103 15
  3828. a117 6
  3829.     do_simple_layout(opts, opts->startperson, (opts->pagewidth - opts->rmargin)/2, opts->title.linespc + 3*opts->person.linespc, 0);
  3830.     do
  3831.     {
  3832.         people_moved = FALSE;
  3833.         adjust_layout(opts, opts->startperson);
  3834.     } while(people_moved);
  3835. d119 2
  3836. d122 7
  3837. d133 2
  3838. d178 4
  3839. a181 4
  3840.     int i, children;
  3841.     int ptwidth, startx, endx, childy;
  3842.     person_t *child;
  3843.     marriage_t *marriage, *m;
  3844. d183 1
  3845. a183 1
  3846.     dbprintf(( "\ndo_simple_layout: do layout for ID %s at: %d,%d\n", id, x,y));
  3847. d185 1
  3848. a185 1
  3849.     marriage = findmarriage(id);
  3850. d198 1
  3851. d202 13
  3852. a214 2
  3853.             child->married = (findmarriage(child->id) != NULL);
  3854.             child->fullname = !streq(child->family, marriage->husband->family) || child->married;
  3855. d216 8
  3856. d225 1
  3857. d227 1
  3858. d247 2
  3859. a248 2
  3860.                 case H_CENTERED:
  3861.                     startx = x - (ptwidth * 0.5);
  3862. d251 1
  3863. a251 1
  3864.                     startx = x - (ptwidth * 0.33);
  3865. d253 3
  3866. a255 2
  3867.                 case H_RIGHT:
  3868.                     startx = x - (ptwidth * 0.67);
  3869. d282 2
  3870. a283 8
  3871.                     if (level <= opts->maxlevel)
  3872.                     {
  3873.                         do_simple_layout(opts, child->id, child->xpos, child->ypos + opts->ticklen+1, level+1);
  3874.                     }
  3875.                     else
  3876.                     {
  3877.                         dbprintf(("do_simple_layout: marriage of %s %s skipped - too many levels.\n", child->firstname, child->family));
  3878.                     }
  3879. d289 15
  3880. a303 1
  3881.         marriage = nextmarriage(marriage, id);
  3882. d305 23
  3883. a327 1
  3884.         x += 
  3885. d330 33
  3886. a362 1
  3887.     dbprintf(( "do_simple_layout: finished simple layout for ID %s.\n", id));
  3888. d365 62
  3889. d455 3
  3890. a457 3
  3891.     person_t *child, *lastchild = NULL;
  3892.     marriage_t *m, *marriage;
  3893.     int newpos, dx;
  3894. d459 2
  3895. a460 4
  3896.     dbprintf(( "adjust_layout: examining tree for ID %s....\n", id));
  3897.  
  3898.     marriage = findmarriage(id);
  3899.     while(marriage)
  3900. d462 2
  3901. a463 2
  3902.         child = marriage->firstchild;
  3903.         while(child != NULL)
  3904. d465 7
  3905. a471 1
  3906.             if (child->married)
  3907. d473 1
  3908. a473 6
  3909.                 adjust_layout(opts, child->id);
  3910.                 m = findmarriage(child->id);
  3911.             }
  3912.             if (child->married && m->children > 0)
  3913.             {
  3914.                 if (lastchild)
  3915. d475 2
  3916. a476 5
  3917.                     newpos = m->firstchild->xpos;
  3918.                     dx = lastchild->xpos - newpos;
  3919.                     dbprintf(("adjust_layout: does child %s overlap %s (%d vs %d) ?",
  3920.                             m->firstchild->firstname, lastchild->firstname,
  3921.                             newpos, lastchild->xpos));
  3922. d478 5
  3923. a482 1
  3924.                     if (dx > 0)
  3925. d484 2
  3926. a485 8
  3927.                         person_t *c1;
  3928.                         
  3929.                         dbprintf((" ... yes\n"));
  3930.                         people_moved = TRUE;
  3931.                         dx += ((lastchild->width + m->firstchild->width) / 2 );
  3932.                         dbprintf(("adjust_layout: dx += (%d + %d)/2 => %d\n",
  3933.                                 lastchild->width, m->firstchild->width, dx));
  3934.                         
  3935. d487 3
  3936. a489 1
  3937.                          * move the current & those right by dx
  3938. d491 4
  3939. a494 2
  3940.                         c1 = child;
  3941.                         while(c1) 
  3942. d496 2
  3943. a497 13
  3944.                             if (c1->married)
  3945.                             {
  3946.                                 marriage_t *m1;
  3947.                                 m1 = findmarriage(c1->id);
  3948.                                 while(m1)
  3949.                                 {
  3950.                                     move_tree(m1, dx);
  3951.                                     m1 = nextmarriage(m1, c1->id);
  3952.                                 }
  3953.                             }
  3954.                             else
  3955.                                 c1->xpos += dx;
  3956.                             c1 = c1->nextchild;
  3957. d499 11
  3958. a510 4
  3959.                     else
  3960.                     {
  3961.                         dbprintf((" ... no\n"));
  3962.                     }
  3963. d512 3
  3964. a514 1
  3965.                 lastchild = m->lastchild;
  3966. a515 1
  3967.             child = child->nextchild;
  3968. d517 6
  3969. a522 4
  3970.         marriage = nextmarriage(marriage, id);
  3971.     }
  3972.     
  3973.     dbprintf(( "adjust_layout: finished examining tree for ID %s...\n", id));
  3974. d549 1
  3975. a549 1
  3976. void move_tree(marriage_t *marriage, int dx)
  3977. d552 1
  3978. a552 1
  3979.     marriage_t *m;
  3980. d554 2
  3981. a555 2
  3982.     dbprintf(( "move_tree: move marriage %s %s by %d\n",
  3983.             marriage->husband->firstname, marriage->wife->family, dx));
  3984. d557 1
  3985. a557 1
  3986.     marriage->xpos += dx;
  3987. d559 1
  3988. a559 1
  3989.     if (marriage->children > 0)
  3990. d561 3
  3991. d565 1
  3992. a565 1
  3993.         while(child != NULL)
  3994. d567 1
  3995. a567 10
  3996.             child->xpos += dx;
  3997.  
  3998.             dbprintf(( "move_tree: move child %s %s by %d\n",
  3999.                     child->firstname, child->family, dx));
  4000.  
  4001.             if (child->married)
  4002.             {
  4003.                 m = findmarriage(child->id);
  4004.                 move_tree(m, dx);
  4005.             }
  4006. a575 92
  4007.  *    Function:    
  4008.  *
  4009.  *
  4010.  *    Inputs:
  4011.  *        outf - the output file to write PostScript to.
  4012.  *        opts - current option set
  4013.  *        id - the ID of the person to start at, who should be
  4014.  *            married.
  4015.  *
  4016.  *    Outputs:
  4017.  *        (file)
  4018.  *
  4019.  *    Error Handling:
  4020.  *        None.
  4021.  *
  4022.  *    Description:
  4023.  *        
  4024.  *        
  4025.  *
  4026.  ************************************************************* 
  4027. )*/
  4028.  
  4029. void print_tree(FILE *outf, options_t *opts, id_t id)
  4030. {
  4031.     person_t *child;
  4032.     marriage_t *m, *marriage;
  4033.     
  4034.     marriage = findmarriage(id);
  4035.     while(marriage)
  4036.     {
  4037.         dbprintf(( "\nprint_tree: marriage at: %d,%d\n", marriage->xpos, marriage->ypos));
  4038.  
  4039.         /*
  4040.          * print this marriage.
  4041.          */
  4042.         printmarriage(outf, opts, marriage, marriage->xpos, marriage->ypos);
  4043.         
  4044.         if (marriage->children > 0)
  4045.         {
  4046.             int gap;
  4047.  
  4048.             dbprintf(( "print_tree: writing %d children ...\n", marriage->children));
  4049.  
  4050.             fprintf(outf, "1 setlinewidth\n");
  4051.  
  4052.             /*
  4053.              * gap allowed for the parents info.
  4054.              */
  4055.             gap = (opts->person.linespc * opts->marrlines) - (opts->ticklen);
  4056.  
  4057.             /*
  4058.              * draw a line 'connecting' the parents
  4059.              * to the children's line.
  4060.              */
  4061.             fprintf(outf, "%d %d moveto %d %d lineto stroke\n",
  4062.                 XOF(opts, marriage->xpos), YOF(opts, marriage->ypos + gap),
  4063.                 XOF(opts, marriage->xpos), YOF(opts, marriage->firstchild->ypos - opts->ticklen));
  4064.  
  4065.             /*
  4066.              * draw the horizontal line connecting 
  4067.              * the children together.
  4068.              */
  4069.             fprintf(outf, "%d %d moveto %d 0 rlineto stroke\n",
  4070.                 XOF(opts, marriage->firstchild->xpos), YOF(opts, marriage->firstchild->ypos - opts->ticklen),
  4071.                 DXOF(opts, marriage->lastchild->xpos - marriage->firstchild->xpos));
  4072.  
  4073.             child = marriage->firstchild;
  4074.             while(child != NULL)
  4075.             {
  4076.                 fprintf(outf, "%d %d moveto 0 %d rlineto stroke\n",
  4077.                     XOF(opts, child->xpos), YOF(opts, child->ypos), DYOF(opts, -opts->ticklen));
  4078.                 
  4079.                 if (child->married)
  4080.                 {
  4081.                     print_tree(outf, opts, child->id);
  4082.                 }
  4083.                 else
  4084.                 {
  4085.                     printperson(outf, opts, child, child->xpos, child->ypos+opts->ticklen+1);
  4086.                 }
  4087.                 child = child->nextchild;
  4088.             }
  4089.         }
  4090.         marriage = nextmarriage(marriage, id);
  4091.     } 
  4092.     
  4093.     dbprintf(( "print_tree: finished writing marriage.\n"));
  4094. }
  4095.  
  4096. /*(
  4097.  ************************************************************* 
  4098.  *
  4099. a597 1
  4100.     person_t *child;
  4101. d610 1
  4102. a610 1
  4103.     w = (opts->person.size * l) / 1.5;
  4104. d619 4
  4105. a622 22
  4106. /*(
  4107.  ************************************************************* 
  4108.  *
  4109.  *    Function:    printperson
  4110.  *
  4111.  *
  4112.  *    Inputs:
  4113.  *        
  4114.  *
  4115.  *    Outputs:
  4116.  *        
  4117.  *
  4118.  *    Error Handling:
  4119.  *        
  4120.  *
  4121.  *    Description:
  4122.  *        
  4123.  *        print an unmarried person centered at the position
  4124.  * (x,y)
  4125.  *
  4126.  ************************************************************* 
  4127. )*/
  4128. d624 1
  4129. a624 1
  4130. void printperson(FILE *outf, options_t *opts, person_t *person, int x, int y)
  4131. d626 2
  4132. a627 2
  4133.     char buf[64];
  4134.     int linepos;
  4135. d629 5
  4136. a633 4
  4137.     linepos = y;
  4138.     fprintf(outf, "%%\n%% print an unmarried person\n%%\n");
  4139.     fprintf(outf, "personfont setfont\n");
  4140.     if (opts->printids)
  4141. d635 2
  4142. a636 3
  4143.         linepos += opts->ident.linespc;
  4144.         fprintf(outf, "%d %d moveto (ID: %s) show\n",
  4145.             XOF(opts, x), YOF(opts, linepos), person->id);
  4146. d638 1
  4147. a638 8
  4148.     fprintf(outf, "%d %d moveto\n", XOF(opts, x), YOF(opts, linepos));
  4149.     if (person->fullname)
  4150.         fprintf(outf, "(%s %s) showcentered\n", person->firstname, person->family);
  4151.     else
  4152.         fprintf(outf, "(%s) showcentered\n", person->firstname);
  4153.     fprintf(outf, "datefont setfont\n");
  4154.     strcpy(buf, "(");
  4155.     if (person->born.known)
  4156. d640 2
  4157. a641 1
  4158.         strcat(buf, date2string(&person->born));
  4159. d643 3
  4160. a645 2
  4161.     strcat(buf, " - ");
  4162.     if (person->died.known)
  4163. d647 39
  4164. a685 1
  4165.         strcat(buf, date2string(&person->died));
  4166. d687 2
  4167. a688 3
  4168.     strcat(buf, ")");
  4169.     fprintf(outf, "%d %d moveto (%s) showcentered\n",
  4170.         XOF(opts, x), YOF(opts, y+opts->person.linespc), buf);
  4171. a690 22
  4172. /*(
  4173.  ************************************************************* 
  4174.  *
  4175.  *    Function:    printmarriage
  4176.  *
  4177.  *
  4178.  *    Inputs:
  4179.  *        
  4180.  *
  4181.  *    Outputs:
  4182.  *        (file)
  4183.  *
  4184.  *    Error Handling:
  4185.  *        none.
  4186.  *
  4187.  *    Description:
  4188.  *        
  4189.  *        print two married people centered at the position
  4190.  * (x,y)
  4191.  *
  4192.  ************************************************************* 
  4193. )*/
  4194. d692 1
  4195. a692 2
  4196. void printmarriage(FILE *outf, options_t *opts, marriage_t *marriage,
  4197.                     int x, int y)
  4198. d694 2
  4199. a695 3
  4200. #if 0
  4201.     char buf[64];
  4202.     int linepos;
  4203. d697 2
  4204. a698 9
  4205.     linepos = y;
  4206.     fprintf(outf, "%%\n%% print a marriage\n%%\n");
  4207.     if (opts->printids)
  4208.     {
  4209.         fprintf(outf, "identfont setfont\n");
  4210.         fprintf(outf, "%d %d moveto\n", XOF(opts, x), YOF(opts, linepos));
  4211.         fprintf(outf, "(ID: %s) show\n", marriage->husband->id);
  4212.         linepos += opts->ident.linespc;
  4213.     }
  4214. a699 22
  4215.     fprintf(outf, "personfont setfont\n");
  4216.     fprintf(outf, "%d %d moveto\n", XOF(opts, x), YOF(opts, linepos));
  4217.     fprintf(outf, "( %s) show\n", marriage->husband->firstname);
  4218.     linepos += opts->person.linespc;
  4219.  
  4220.     fprintf(outf, "%d %d moveto\n", XOF(opts, x), YOF(opts, linepos));
  4221.     fprintf(outf, "( %s) show\n", marriage->husband->family);
  4222.     linepos += opts->person.linespc;
  4223.     strcpy(buf, "(");
  4224.     if (marriage->husband->born.known)
  4225.     {
  4226.         strcat(buf, date2string(&marriage->husband->born));
  4227.     }
  4228.     strcat(buf, " - ");
  4229.     if (marriage->husband->died.known)
  4230.     {
  4231.         strcat(buf, date2string(&marriage->husband->died));
  4232.     }
  4233.     strcat(buf, ")");
  4234.     fprintf(outf, "datefont setfont\n");
  4235.     fprintf(outf, "%d %d moveto (%s) show\n", XOF(opts, x+1), YOF(opts, linepos), buf);
  4236.  
  4237. d701 2
  4238. a702 1
  4239.      * deal with the wife.
  4240. d704 2
  4241. a705 2
  4242.     linepos = y;
  4243.     if (opts->printids)
  4244. d707 6
  4245. a712 12
  4246.         fprintf(outf, "identfont setfont\n");
  4247.         fprintf(outf, "%d %d moveto\n", XOF(opts, x), YOF(opts, linepos));
  4248.         fprintf(outf, "(ID: %s) showright\n", marriage->wife->id);
  4249.         linepos += opts->ident.linespc;
  4250.     }
  4251.     fprintf(outf, "personfont setfont\n");
  4252.     fprintf(outf, "%d %d moveto\n", XOF(opts, x), YOF(opts, linepos));
  4253.     fprintf(outf, "(%s ) showright\n", marriage->wife->firstname);
  4254.     linepos += opts->person.linespc;
  4255.     fprintf(outf, "%d %d moveto\n", XOF(opts, x), YOF(opts, linepos));
  4256.     fprintf(outf, "(%s ) showright\n", marriage->wife->family);
  4257.     linepos += opts->person.linespc;
  4258. d714 35
  4259. a748 4
  4260.     strcpy(buf, "(");
  4261.     if (marriage->wife->born.known)
  4262.     {
  4263.         strcat(buf, date2string(&marriage->wife->born));
  4264. a749 11
  4265.     strcat(buf, " - ");
  4266.     if (marriage->wife->died.known)
  4267.     {
  4268.         strcat(buf, date2string(&marriage->wife->died));
  4269.     }
  4270.     strcat(buf, ")");
  4271.     fprintf(outf, "datefont setfont\n");
  4272.     fprintf(outf, "%d %d moveto (%s) showright\n", XOF(opts, x-1), YOF(opts, linepos), buf);
  4273. #else
  4274.     char buf[64];
  4275.     int linepos;
  4276. d751 3
  4277. a753 6
  4278.     linepos = y;
  4279.     fprintf(outf, "%%\n%% print a marriage\n%%\n");
  4280.     fprintf(outf, "personfont setfont\n");
  4281.     fprintf(outf, "%d %d moveto\n", XOF(opts, x), YOF(opts, linepos));
  4282.     fprintf(outf, "(%s %s) showcentered\n", marriage->husband->firstname, marriage->husband->family);
  4283.     linepos += opts->person.linespc;
  4284. a754 7
  4285.     if (opts->printids)
  4286.     {
  4287.         fprintf(outf, "identfont setfont\n");
  4288.         fprintf(outf, "%d %d moveto\n", XOF(opts, x), YOF(opts, linepos));
  4289.         fprintf(outf, "(ID: %s) show\n", marriage->husband->id);
  4290.         linepos += opts->ident.linespc;
  4291.     }
  4292. d756 4
  4293. a759 14
  4294.     strcpy(buf, "(");
  4295.     if (marriage->husband->born.known)
  4296.     {
  4297.         strcat(buf, date2string(&marriage->husband->born));
  4298.     }
  4299.     strcat(buf, " - ");
  4300.     if (marriage->husband->died.known)
  4301.     {
  4302.         strcat(buf, date2string(&marriage->husband->died));
  4303.     }
  4304.     strcat(buf, ")");
  4305.     fprintf(outf, "datefont setfont\n");
  4306.     fprintf(outf, "%d %d moveto (%s) showcentered\n", XOF(opts, x), YOF(opts, linepos), buf);
  4307.     linepos += opts->person.linespc;
  4308. d761 4
  4309. a764 6
  4310.     /*
  4311.      * put an '=' between the people
  4312.      */
  4313.     fprintf(outf, "%d %d moveto\n", XOF(opts, x), YOF(opts, linepos));
  4314.     fprintf(outf, "(=) showcentered\n");
  4315.     linepos += opts->person.linespc;
  4316. d766 3
  4317. a768 7
  4318.     /*
  4319.      * deal with the wife.
  4320.      */
  4321.     fprintf(outf, "personfont setfont\n");
  4322.     fprintf(outf, "%d %d moveto\n", XOF(opts, x), YOF(opts, linepos));
  4323.     fprintf(outf, "(%s %s) showcentered\n", marriage->wife->firstname, marriage->wife->family);
  4324.     linepos += opts->person.linespc;
  4325. d770 1
  4326. a770 1
  4327.     if (opts->printids)
  4328. d772 2
  4329. a773 4
  4330.         fprintf(outf, "identfont setfont\n");
  4331.         fprintf(outf, "%d %d moveto\n", XOF(opts, x), YOF(opts, linepos));
  4332.         fprintf(outf, "(ID: %s) showcentered\n", marriage->wife->id);
  4333.         linepos += opts->ident.linespc;
  4334. d775 1
  4335. a775 3
  4336.  
  4337.     strcpy(buf, "(");
  4338.     if (marriage->wife->born.known)
  4339. d777 2
  4340. a778 1
  4341.         strcat(buf, date2string(&marriage->wife->born));
  4342. d780 3
  4343. a782 2
  4344.     strcat(buf, " - ");
  4345.     if (marriage->wife->died.known)
  4346. d784 10
  4347. a793 7
  4348.         strcat(buf, date2string(&marriage->wife->died));
  4349.     }
  4350.     strcat(buf, ")");
  4351.     fprintf(outf, "datefont setfont\n");
  4352.     fprintf(outf, "%d %d moveto (%s) showcentered\n", XOF(opts, x), YOF(opts, linepos), buf);
  4353. #endif
  4354. }
  4355. d795 6
  4356. a800 23
  4357. /*(
  4358.  ************************************************************* 
  4359.  *
  4360.  *    Function:    do_title
  4361.  *
  4362.  *
  4363.  *    Inputs:
  4364.  *        outf - file to write PostScript to
  4365.  *        opts - option settings, including the title etc.
  4366.  *
  4367.  *    Outputs:
  4368.  *        (file)
  4369.  *
  4370.  *    Error Handling:
  4371.  *        none.
  4372.  *
  4373.  *    Description:
  4374.  *        
  4375.  *        To print the title string of the tree. Optionally, to
  4376.  * place it in a grey box.
  4377.  *
  4378.  ************************************************************* 
  4379. )*/
  4380. d802 9
  4381. a810 5
  4382. void do_title(FILE *outf, options_t *opts)
  4383. {
  4384.     int h;
  4385.     int lx, ty, rx, by;
  4386.     float ptsz = opts->title.size;
  4387. d812 11
  4388. a822 12
  4389.     fprintf(outf, "%%\n%% Draw the page title\n%%\n");
  4390.     if (opts->titlegreylevel < 1.0)
  4391.     {
  4392.         fprintf(outf, "%.3f setgray\n", opts->titlegreylevel);
  4393.         lx = 0;
  4394.         ty = 0;
  4395.         rx = opts->pagewidth - opts->rmargin;
  4396.         by = opts->title.size * 1.7;
  4397.         fprintf(outf, "%d %d moveto %d %d lineto %d %d lineto %d %d lineto\n",
  4398.                 XOF(opts, lx),    YOF(opts, ty),    XOF(opts, rx),    YOF(opts, ty),
  4399.                 XOF(opts, rx),    YOF(opts, by),    XOF(opts, lx),    YOF(opts, by));
  4400.         fprintf(outf, "closepath gsave fill grestore 0 setgray stroke\n");
  4401. a823 4
  4402.     fprintf(outf, "titlefont setfont\n");
  4403.     fprintf(outf, "%d %d moveto (%s) showcentered\n",
  4404.             XOF(opts, opts->pagewidth/2), YOF(opts, opts->title.linespc), opts->titlestr);
  4405. }
  4406. d825 1
  4407. a825 62
  4408. /*(
  4409.  ************************************************************* 
  4410.  *
  4411.  *    Function:    do_prolog
  4412.  *
  4413.  *
  4414.  *    Inputs:
  4415.  *        outf - the file to write to
  4416.  *        opts - the current options set
  4417.  *
  4418.  *    Outputs:
  4419.  *        None.
  4420.  *
  4421.  *    Error Handling:
  4422.  *        None.
  4423.  *
  4424.  *    Description:
  4425.  *        
  4426.  *        To output the appropriate DSC comments for the output
  4427.  * file and generate definitions of private procedures.
  4428.  *
  4429.  ************************************************************* 
  4430. )*/
  4431. void do_prolog(FILE *outf, options_t *opts)
  4432. {
  4433.     time_t now;
  4434.  
  4435.     time(&now);
  4436.     fprintf(outf, "%%!PS-Adobe-3.0\n");
  4437.     fprintf(outf, "%%%%BoundingBox: (atend)\n");
  4438.     fprintf(outf, "%%%%CreatorTitle: Ftree version " VERSION " (" __DATE__ ")\n");
  4439.     fprintf(outf, "%%%%CreationDate: %s", ctime(&now));
  4440.     fprintf(outf, "%%%%DocumentSuppliedResources: font %s %s %s\n",
  4441.                         opts->title.font, opts->ident.font, opts->person.font);
  4442.     fprintf(outf, "%%%%Pages: 1\n");
  4443.     fprintf(outf, "\n");
  4444.     fprintf(outf, "%%%%Page: 1 1\n");
  4445.     fprintf(outf, "%%%%BeginPageSetup\n");
  4446.     fprintf(outf, "10 dict begin\n");
  4447.     fprintf(outf, "systemdict /%s known { %s } if\n", opts->papertype, opts->papertype);
  4448.     fprintf(outf, "/showcentered {                %% str showc -- \n");
  4449.     fprintf(outf, "dup stringwidth pop 2 div neg 0 rmoveto show\n");
  4450.     fprintf(outf, "} def\n");
  4451.     fprintf(outf, "/showright {                   %% str showc -- \n");
  4452.     fprintf(outf, "dup stringwidth pop neg 0 rmoveto show\n");
  4453.     fprintf(outf, "} def\n");
  4454.     fprintf(outf, "/fsf {findfont exch scalefont def} bind def\n");
  4455.     fprintf(outf, "/identfont %.1f /%s fsf\n", opts->ident.size, opts->ident.font);
  4456.     fprintf(outf, "/personfont %.1f /%s fsf\n", opts->person.size, opts->person.font);
  4457.     fprintf(outf, "/titlefont %.1f /%s fsf\n", opts->title.size, opts->title.font);
  4458.     fprintf(outf, "/datefont %.1f /%s fsf\n", opts->person.size-2, opts->person.font);
  4459.     if (opts->landscape)
  4460.     {
  4461.         fprintf(outf, "%%%%PageOrientation: Landscape\n");
  4462.         fprintf(outf, "gsave clippath pathbbox grestore\n");
  4463.         fprintf(outf, "4 dict begin /ury exch def /urx exch def /lly exch def /llx exch def\n");
  4464.         fprintf(outf, "-90 rotate urx neg lly neg translate\n");
  4465.         fprintf(outf, "end\n");
  4466.     }
  4467.     else
  4468.         fprintf(outf, "%%%%PageOrientation: Portrait\n");
  4469.     fprintf(outf, "%%%%EndPageSetup\n");
  4470. a827 23
  4471. /*(
  4472.  ************************************************************* 
  4473.  *
  4474.  *    Function:    do_epilog
  4475.  *
  4476.  *
  4477.  *    Inputs:
  4478.  *        outf - the file to write to
  4479.  *        opts - the current options set
  4480.  *
  4481.  *    Outputs:
  4482.  *        none.
  4483.  *
  4484.  *    Error Handling:
  4485.  *        none.
  4486.  *
  4487.  *    Description:
  4488.  *        
  4489.  *        To close off the postscript program with showpage and
  4490.  * appropriate DSC comments.
  4491.  *
  4492.  ************************************************************* 
  4493. )*/
  4494. d829 1
  4495. a829 1
  4496. void do_epilog(FILE *outf, options_t *opts)
  4497. d831 2
  4498. a832 8
  4499.     fprintf(outf, "showpage\n");
  4500.     fprintf(outf, "end         %% of dict begin\n");
  4501.     fprintf(outf, "%%%%EndPage: 1 1\n");
  4502.     fprintf(outf, "%%%%Trailer:\n");
  4503.     fprintf(outf, "%%%%BoundingBox: %d %d %d %d\n",
  4504.                 opts->bblx, opts->bbly, opts->bbux, opts->bbuy);
  4505.     fprintf(outf, "%%%%EOF\n");
  4506. }
  4507. d834 2
  4508. a835 25
  4509. /*(
  4510.  ************************************************************* 
  4511.  *
  4512.  *    Function:    date2string
  4513.  *
  4514.  *
  4515.  *    Inputs:
  4516.  *        d - pointer to a struct date
  4517.  *
  4518.  *    Outputs:
  4519.  *        char * - pointer to a statically allocated buffer
  4520.  *
  4521.  *    Error Handling:
  4522.  *        Copes with various forms of unknown date by placing
  4523.  * '?' characters in the returned string. Copes with 'd'
  4524.  * being NULL by returning "".
  4525.  *
  4526.  *    Description:
  4527.  *        
  4528.  *        Formats a date into a string, accounting for the
  4529.  * values of some of the fields being unknown. The date format
  4530.  * is predefined and unchangeable.
  4531.  *
  4532.  ************************************************************* 
  4533. )*/
  4534. d837 1
  4535. a837 15
  4536. char *date2string(struct date *d)
  4537. {
  4538.     static char buf[32];
  4539.     char tbuf[12];
  4540.  
  4541.     buf[0] = '\0';
  4542.     if (d == NULL)
  4543.         return;
  4544.     
  4545.     if (d->dvalid)
  4546.         sprintf(buf, "%d/", d->day);
  4547.     else
  4548.         strcpy(buf, "?/");
  4549.  
  4550.     if (d->mvalid)
  4551. d839 2
  4552. a840 2
  4553.         sprintf(tbuf, "%d/", d->month);
  4554.         strcat(buf, tbuf);
  4555. d842 3
  4556. a844 4
  4557.     else
  4558.         strcat(buf, "?/");
  4559.  
  4560.     if (d->yvalid)
  4561. d846 6
  4562. a851 5
  4563.         sprintf(tbuf, "%d", d->year);
  4564.         strcat(buf, tbuf);
  4565.     }
  4566.     else
  4567.         strcat(buf, "?");
  4568. d853 20
  4569. a872 3
  4570.     dbprintf(( "date2string: buf : %s\n", buf));
  4571.     return buf;
  4572. }
  4573. d874 14
  4574. a887 33
  4575.  
  4576. /*(
  4577.  ************************************************************* 
  4578.  *
  4579.  *    Function:    widthof
  4580.  *
  4581.  *
  4582.  *    Inputs:
  4583.  *        
  4584.  *
  4585.  *    Outputs:
  4586.  *        
  4587.  *
  4588.  *    Error Handling:
  4589.  *        
  4590.  *
  4591.  *    Description:
  4592.  *        
  4593.  *        return the width required to print 'person'
  4594.  *
  4595.  ************************************************************* 
  4596. )*/
  4597.  
  4598. int widthof(options_t *opts, person_t *pers)
  4599. {
  4600.     int w;
  4601.     person_t *child;
  4602.     int l;
  4603.  
  4604.     if (pers->fullname)
  4605.     {
  4606.         l = strlen(pers->family);
  4607.         l += strlen(pers->firstname);
  4608. a888 4
  4609.     else
  4610.     {
  4611.         l = strlen(pers->firstname);
  4612.     }
  4613. d890 2
  4614. a891 6
  4615.     w = (opts->person.size * l) / 1.5;
  4616.     w = w + TREE_GAP;
  4617.  
  4618.     dbprintf(( "widthof: %s width of \"%s\" is \t%d (%dc).\n", 
  4619.         (pers->fullname)?"full":"short", pers->firstname, w, l));
  4620.     return w;
  4621. @
  4622.