Fossil

Check-in [e685fc0b]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Draw inbound merge arrows on the graph even if the merge parent is off-screen.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:e685fc0b858596f76d3389ba4bc56d0d3f57719f
User & Date: drh 2010-12-22 14:25:55
Context
2010-12-22
16:06
Documentation updates. check-in: c1c18b72 user: drh tags: trunk
14:25
Draw inbound merge arrows on the graph even if the merge parent is off-screen. check-in: e685fc0b user: drh tags: trunk
01:32
Fix up all of the test scripts so that the test results match the latest fossil output. Ticket [4f43f7ff92ae02ae3] check-in: 1092a1df user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/graph.c.

19
20
21
22
23
24
25
26
27
28
29
30


31
32
33
34
35
36
37
..
45
46
47
48
49
50
51

52
53
54
55
56
57
58
...
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
...
396
397
398
399
400
401
402
403










404
405
406
407
408
409
410
411
412
413
414

415
416
417
418
419
420
421
...
439
440
441
442
443
444
445

446
447
*/
#include "config.h"
#include "graph.h"
#include <assert.h>

#if INTERFACE

#define GR_MAX_PARENT 10      /* Most parents for any one node */
#define GR_MAX_RAIL   32      /* Max number of "rails" to display */

/* The graph appears vertically beside a timeline.  Each row in the
** timeline corresponds to a row in the graph.


*/
struct GraphRow {
  int rid;                    /* The rid for the check-in */
  int nParent;                /* Number of parents */
  int aParent[GR_MAX_PARENT]; /* Array of parents.  0 element is primary .*/
  char *zBranch;              /* Branch name */
  char *zBgClr;               /* Background Color */
................................................................................
  u8 isDup;                   /* True if this is duplicate of a prior entry */
  int iRail;                  /* Which rail this check-in appears on. 0-based.*/
  int aiRaiser[GR_MAX_RAIL];  /* Raisers from this node to a higher row. */
  int bDescender;             /* Raiser from bottom of graph to here. */
  u32 mergeIn;                /* Merge in from other rails */
  int mergeOut;               /* Merge out to this rail */
  int mergeUpto;              /* Draw the merge rail up to this level */


  u32 railInUse;              /* Mask of occupied rails */
};

/* Context while building a graph
*/
struct GraphContext {
................................................................................
      hasDup = 1;
      pDup->isDup = 1;
    }
    hashInsert(p, pRow, 1);
  }
  p->mxRail = -1;

  /* Purge merge-parents that are out-of-graph.
  **
  ** Each node has one primary parent and zero or more "merge" parents.
  ** A merge parent is a prior checkin from which changes were merged into
  ** the current check-in.  If a merge parent is not in the visible section
  ** of this graph, then no arrows will be drawn for it, so remove it from
  ** the aParent[] array.
  */
  for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
    for(i=1; i<pRow->nParent; i++){
      if( hashFind(p, pRow->aParent[i])==0 ){
        pRow->aParent[i] = pRow->aParent[--pRow->nParent];
        i--;
      }
    }
  }

  /* Find the pChild pointer for each node. 
  **
  ** The pChild points to the node directly above on the same rail.
  ** The pChild must be in the same branch.  Leaf nodes have a NULL
  ** pChild.
  **
  ** In the case of a fork, choose the pChild that results in the
................................................................................
  /*
  ** Insert merge rails and merge arrows
  */
  for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
    for(i=1; i<pRow->nParent; i++){
      int parentRid = pRow->aParent[i];
      pDesc = hashFind(p, parentRid);
      if( pDesc==0 ) continue;










      if( pDesc->mergeOut<0 ){
        int iTarget = (pRow->iRail + pDesc->iRail)/2;
        pDesc->mergeOut = findFreeRail(p, pRow->idx, pDesc->idx-1, 0, iTarget);
        pDesc->mergeUpto = pRow->idx;
        mask = 1<<pDesc->mergeOut;
        for(pLoop=pRow->pNext; pLoop && pLoop->rid!=parentRid;
             pLoop=pLoop->pNext){
          pLoop->railInUse |= mask;
        }
      }
      pRow->mergeIn |= 1<<pDesc->mergeOut;

    }
  }

  /*
  ** Insert merge rails from primaries to duplicates. 
  */
  if( hasDup ){
................................................................................
  /*
  ** Find the maximum rail number.
  */
  p->mxRail = 0;
  for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
    if( pRow->iRail>p->mxRail ) p->mxRail = pRow->iRail;
    if( pRow->mergeOut>p->mxRail ) p->mxRail = pRow->mergeOut;

  }
}







|



|
>
>







 







>







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







|
>
>
>
>
>
>
>
>
>
>
|
|
|
|
|
|
|
|
|
|
|
>







 







>


19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
..
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
...
278
279
280
281
282
283
284

















285
286
287
288
289
290
291
...
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
...
436
437
438
439
440
441
442
443
444
445
*/
#include "config.h"
#include "graph.h"
#include <assert.h>

#if INTERFACE

#define GR_MAX_PARENT 10      /* Max number of parents for any one node */
#define GR_MAX_RAIL   32      /* Max number of "rails" to display */

/* The graph appears vertically beside a timeline.  Each row in the
** timeline corresponds to a row in the graph.  GraphRow.idx is 0 for
** the top-most row and increases moving down.  Hence (in the absence of
** time skew) parents have a larger index than their children.
*/
struct GraphRow {
  int rid;                    /* The rid for the check-in */
  int nParent;                /* Number of parents */
  int aParent[GR_MAX_PARENT]; /* Array of parents.  0 element is primary .*/
  char *zBranch;              /* Branch name */
  char *zBgClr;               /* Background Color */
................................................................................
  u8 isDup;                   /* True if this is duplicate of a prior entry */
  int iRail;                  /* Which rail this check-in appears on. 0-based.*/
  int aiRaiser[GR_MAX_RAIL];  /* Raisers from this node to a higher row. */
  int bDescender;             /* Raiser from bottom of graph to here. */
  u32 mergeIn;                /* Merge in from other rails */
  int mergeOut;               /* Merge out to this rail */
  int mergeUpto;              /* Draw the merge rail up to this level */
  u32 mergeDown;              /* Draw merge lines up from bottom of graph */

  u32 railInUse;              /* Mask of occupied rails */
};

/* Context while building a graph
*/
struct GraphContext {
................................................................................
      hasDup = 1;
      pDup->isDup = 1;
    }
    hashInsert(p, pRow, 1);
  }
  p->mxRail = -1;


















  /* Find the pChild pointer for each node. 
  **
  ** The pChild points to the node directly above on the same rail.
  ** The pChild must be in the same branch.  Leaf nodes have a NULL
  ** pChild.
  **
  ** In the case of a fork, choose the pChild that results in the
................................................................................
  /*
  ** Insert merge rails and merge arrows
  */
  for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
    for(i=1; i<pRow->nParent; i++){
      int parentRid = pRow->aParent[i];
      pDesc = hashFind(p, parentRid);
      if( pDesc==0 ){
        /* Merge from a node that is off-screen */
        int iMrail = findFreeRail(p, pRow->idx, p->nRow, 0, 0);
        mask = 1<<iMrail;
        pRow->mergeIn |= mask;
        pRow->mergeDown |= mask;
        for(pLoop=pRow->pNext; pLoop; pLoop=pLoop->pNext){
          pLoop->railInUse |= mask;
        }
      }else{
        /* Merge from an on-screen node */
        if( pDesc->mergeOut<0 ){
          int iTarget = (pRow->iRail + pDesc->iRail)/2;
          pDesc->mergeOut = findFreeRail(p, pRow->idx, pDesc->idx-1,0,iTarget);
          pDesc->mergeUpto = pRow->idx;
          mask = 1<<pDesc->mergeOut;
          for(pLoop=pRow->pNext; pLoop && pLoop->rid!=parentRid;
               pLoop=pLoop->pNext){
            pLoop->railInUse |= mask;
          }
        }
        pRow->mergeIn |= 1<<pDesc->mergeOut;
      }
    }
  }

  /*
  ** Insert merge rails from primaries to duplicates. 
  */
  if( hasDup ){
................................................................................
  /*
  ** Find the maximum rail number.
  */
  p->mxRail = 0;
  for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
    if( pRow->iRail>p->mxRail ) p->mxRail = pRow->iRail;
    if( pRow->mergeOut>p->mxRail ) p->mxRail = pRow->mergeOut;
    while( pRow->mergeDown>((1<<(p->mxRail+1))-1) ) p->mxRail++;
  }
}

Changes to src/timeline.c.

350
351
352
353
354
355
356
357
358
359
360
361
362
363

364
365
366
367
368
369
370
...
483
484
485
486
487
488
489



490
491
492
493
494
495
496
    GraphRow *pRow;
    int i;
    char cSep;
    @ <script  type="text/JavaScript">
    @ /* <![CDATA[ */
    cgi_printf("var rowinfo = [\n");
    for(pRow=pGraph->pFirst; pRow; pRow=pRow->pNext){
      cgi_printf("{id:\"m%d\",bg:\"%s\",r:%d,d:%d,mo:%d,mu:%d,u:%d,au:",
        pRow->idx,
        pRow->zBgClr,
        pRow->iRail,
        pRow->bDescender,
        pRow->mergeOut,
        pRow->mergeUpto,

        pRow->aiRaiser[pRow->iRail]
      );
      cSep = '[';
      for(i=0; i<GR_MAX_RAIL; i++){
        if( i==pRow->iRail ) continue;
        if( pRow->aiRaiser[i]>0 ){
          cgi_printf("%c%d,%d", cSep, i, pRow->aiRaiser[i]);
................................................................................
    @     var y0 = p.y+5;
    @     var mx = p.mi[j]*20 + left;
    @     if( mx>p.x ){
    @       drawThinArrow(y0,mx,p.x+6);
    @     }else{
    @       drawThinArrow(y0,mx,p.x-5);
    @     }



    @   }
    @ }
    @ function renderGraph(){
    @   var canvasDiv = document.getElementById("canvas");
    @   while( canvasDiv.hasChildNodes() ){
    @     canvasDiv.removeChild(canvasDiv.firstChild);
    @   }







|






>







 







>
>
>







350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
...
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
    GraphRow *pRow;
    int i;
    char cSep;
    @ <script  type="text/JavaScript">
    @ /* <![CDATA[ */
    cgi_printf("var rowinfo = [\n");
    for(pRow=pGraph->pFirst; pRow; pRow=pRow->pNext){
      cgi_printf("{id:\"m%d\",bg:\"%s\",r:%d,d:%d,mo:%d,mu:%d,md:%u,u:%d,au:",
        pRow->idx,
        pRow->zBgClr,
        pRow->iRail,
        pRow->bDescender,
        pRow->mergeOut,
        pRow->mergeUpto,
        pRow->mergeDown,
        pRow->aiRaiser[pRow->iRail]
      );
      cSep = '[';
      for(i=0; i<GR_MAX_RAIL; i++){
        if( i==pRow->iRail ) continue;
        if( pRow->aiRaiser[i]>0 ){
          cgi_printf("%c%d,%d", cSep, i, pRow->aiRaiser[i]);
................................................................................
    @     var y0 = p.y+5;
    @     var mx = p.mi[j]*20 + left;
    @     if( mx>p.x ){
    @       drawThinArrow(y0,mx,p.x+6);
    @     }else{
    @       drawThinArrow(y0,mx,p.x-5);
    @     }
    @     if( (1<<p.mi[j])&p.md ){
    @       drawThinLine(mx,y0,mx,btm);
    @     }
    @   }
    @ }
    @ function renderGraph(){
    @   var canvasDiv = document.getElementById("canvas");
    @   while( canvasDiv.hasChildNodes() ){
    @     canvasDiv.removeChild(canvasDiv.firstChild);
    @   }