Fossil SCM

Draw inbound merge arrows on the graph even if the merge parent is off-screen.

drh 2010-12-22 14:25 trunk
Commit e685fc0b858596f76d3389ba4bc56d0d3f57719f
2 files changed +26 -28 +5 -1
+26 -28
--- src/graph.c
+++ src/graph.c
@@ -21,15 +21,17 @@
2121
#include "graph.h"
2222
#include <assert.h>
2323
2424
#if INTERFACE
2525
26
-#define GR_MAX_PARENT 10 /* Most parents for any one node */
26
+#define GR_MAX_PARENT 10 /* Max number of parents for any one node */
2727
#define GR_MAX_RAIL 32 /* Max number of "rails" to display */
2828
2929
/* The graph appears vertically beside a timeline. Each row in the
30
-** timeline corresponds to a row in the graph.
30
+** timeline corresponds to a row in the graph. GraphRow.idx is 0 for
31
+** the top-most row and increases moving down. Hence (in the absence of
32
+** time skew) parents have a larger index than their children.
3133
*/
3234
struct GraphRow {
3335
int rid; /* The rid for the check-in */
3436
int nParent; /* Number of parents */
3537
int aParent[GR_MAX_PARENT]; /* Array of parents. 0 element is primary .*/
@@ -47,10 +49,11 @@
4749
int aiRaiser[GR_MAX_RAIL]; /* Raisers from this node to a higher row. */
4850
int bDescender; /* Raiser from bottom of graph to here. */
4951
u32 mergeIn; /* Merge in from other rails */
5052
int mergeOut; /* Merge out to this rail */
5153
int mergeUpto; /* Draw the merge rail up to this level */
54
+ u32 mergeDown; /* Draw merge lines up from bottom of graph */
5255
5356
u32 railInUse; /* Mask of occupied rails */
5457
};
5558
5659
/* Context while building a graph
@@ -277,27 +280,10 @@
277280
}
278281
hashInsert(p, pRow, 1);
279282
}
280283
p->mxRail = -1;
281284
282
- /* Purge merge-parents that are out-of-graph.
283
- **
284
- ** Each node has one primary parent and zero or more "merge" parents.
285
- ** A merge parent is a prior checkin from which changes were merged into
286
- ** the current check-in. If a merge parent is not in the visible section
287
- ** of this graph, then no arrows will be drawn for it, so remove it from
288
- ** the aParent[] array.
289
- */
290
- for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
291
- for(i=1; i<pRow->nParent; i++){
292
- if( hashFind(p, pRow->aParent[i])==0 ){
293
- pRow->aParent[i] = pRow->aParent[--pRow->nParent];
294
- i--;
295
- }
296
- }
297
- }
298
-
299285
/* Find the pChild pointer for each node.
300286
**
301287
** The pChild points to the node directly above on the same rail.
302288
** The pChild must be in the same branch. Leaf nodes have a NULL
303289
** pChild.
@@ -398,22 +384,33 @@
398384
*/
399385
for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
400386
for(i=1; i<pRow->nParent; i++){
401387
int parentRid = pRow->aParent[i];
402388
pDesc = hashFind(p, parentRid);
403
- if( pDesc==0 ) continue;
404
- if( pDesc->mergeOut<0 ){
405
- int iTarget = (pRow->iRail + pDesc->iRail)/2;
406
- pDesc->mergeOut = findFreeRail(p, pRow->idx, pDesc->idx-1, 0, iTarget);
407
- pDesc->mergeUpto = pRow->idx;
408
- mask = 1<<pDesc->mergeOut;
409
- for(pLoop=pRow->pNext; pLoop && pLoop->rid!=parentRid;
410
- pLoop=pLoop->pNext){
389
+ if( pDesc==0 ){
390
+ /* Merge from a node that is off-screen */
391
+ int iMrail = findFreeRail(p, pRow->idx, p->nRow, 0, 0);
392
+ mask = 1<<iMrail;
393
+ pRow->mergeIn |= mask;
394
+ pRow->mergeDown |= mask;
395
+ for(pLoop=pRow->pNext; pLoop; pLoop=pLoop->pNext){
411396
pLoop->railInUse |= mask;
412397
}
398
+ }else{
399
+ /* Merge from an on-screen node */
400
+ if( pDesc->mergeOut<0 ){
401
+ int iTarget = (pRow->iRail + pDesc->iRail)/2;
402
+ pDesc->mergeOut = findFreeRail(p, pRow->idx, pDesc->idx-1,0,iTarget);
403
+ pDesc->mergeUpto = pRow->idx;
404
+ mask = 1<<pDesc->mergeOut;
405
+ for(pLoop=pRow->pNext; pLoop && pLoop->rid!=parentRid;
406
+ pLoop=pLoop->pNext){
407
+ pLoop->railInUse |= mask;
408
+ }
409
+ }
410
+ pRow->mergeIn |= 1<<pDesc->mergeOut;
413411
}
414
- pRow->mergeIn |= 1<<pDesc->mergeOut;
415412
}
416413
}
417414
418415
/*
419416
** Insert merge rails from primaries to duplicates.
@@ -441,7 +438,8 @@
441438
*/
442439
p->mxRail = 0;
443440
for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
444441
if( pRow->iRail>p->mxRail ) p->mxRail = pRow->iRail;
445442
if( pRow->mergeOut>p->mxRail ) p->mxRail = pRow->mergeOut;
443
+ while( pRow->mergeDown>((1<<(p->mxRail+1))-1) ) p->mxRail++;
446444
}
447445
}
448446
--- src/graph.c
+++ src/graph.c
@@ -21,15 +21,17 @@
21 #include "graph.h"
22 #include <assert.h>
23
24 #if INTERFACE
25
26 #define GR_MAX_PARENT 10 /* Most parents for any one node */
27 #define GR_MAX_RAIL 32 /* Max number of "rails" to display */
28
29 /* The graph appears vertically beside a timeline. Each row in the
30 ** timeline corresponds to a row in the graph.
 
 
31 */
32 struct GraphRow {
33 int rid; /* The rid for the check-in */
34 int nParent; /* Number of parents */
35 int aParent[GR_MAX_PARENT]; /* Array of parents. 0 element is primary .*/
@@ -47,10 +49,11 @@
47 int aiRaiser[GR_MAX_RAIL]; /* Raisers from this node to a higher row. */
48 int bDescender; /* Raiser from bottom of graph to here. */
49 u32 mergeIn; /* Merge in from other rails */
50 int mergeOut; /* Merge out to this rail */
51 int mergeUpto; /* Draw the merge rail up to this level */
 
52
53 u32 railInUse; /* Mask of occupied rails */
54 };
55
56 /* Context while building a graph
@@ -277,27 +280,10 @@
277 }
278 hashInsert(p, pRow, 1);
279 }
280 p->mxRail = -1;
281
282 /* Purge merge-parents that are out-of-graph.
283 **
284 ** Each node has one primary parent and zero or more "merge" parents.
285 ** A merge parent is a prior checkin from which changes were merged into
286 ** the current check-in. If a merge parent is not in the visible section
287 ** of this graph, then no arrows will be drawn for it, so remove it from
288 ** the aParent[] array.
289 */
290 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
291 for(i=1; i<pRow->nParent; i++){
292 if( hashFind(p, pRow->aParent[i])==0 ){
293 pRow->aParent[i] = pRow->aParent[--pRow->nParent];
294 i--;
295 }
296 }
297 }
298
299 /* Find the pChild pointer for each node.
300 **
301 ** The pChild points to the node directly above on the same rail.
302 ** The pChild must be in the same branch. Leaf nodes have a NULL
303 ** pChild.
@@ -398,22 +384,33 @@
398 */
399 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
400 for(i=1; i<pRow->nParent; i++){
401 int parentRid = pRow->aParent[i];
402 pDesc = hashFind(p, parentRid);
403 if( pDesc==0 ) continue;
404 if( pDesc->mergeOut<0 ){
405 int iTarget = (pRow->iRail + pDesc->iRail)/2;
406 pDesc->mergeOut = findFreeRail(p, pRow->idx, pDesc->idx-1, 0, iTarget);
407 pDesc->mergeUpto = pRow->idx;
408 mask = 1<<pDesc->mergeOut;
409 for(pLoop=pRow->pNext; pLoop && pLoop->rid!=parentRid;
410 pLoop=pLoop->pNext){
411 pLoop->railInUse |= mask;
412 }
 
 
 
 
 
 
 
 
 
 
 
 
 
413 }
414 pRow->mergeIn |= 1<<pDesc->mergeOut;
415 }
416 }
417
418 /*
419 ** Insert merge rails from primaries to duplicates.
@@ -441,7 +438,8 @@
441 */
442 p->mxRail = 0;
443 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
444 if( pRow->iRail>p->mxRail ) p->mxRail = pRow->iRail;
445 if( pRow->mergeOut>p->mxRail ) p->mxRail = pRow->mergeOut;
 
446 }
447 }
448
--- src/graph.c
+++ src/graph.c
@@ -21,15 +21,17 @@
21 #include "graph.h"
22 #include <assert.h>
23
24 #if INTERFACE
25
26 #define GR_MAX_PARENT 10 /* Max number of parents for any one node */
27 #define GR_MAX_RAIL 32 /* Max number of "rails" to display */
28
29 /* The graph appears vertically beside a timeline. Each row in the
30 ** timeline corresponds to a row in the graph. GraphRow.idx is 0 for
31 ** the top-most row and increases moving down. Hence (in the absence of
32 ** time skew) parents have a larger index than their children.
33 */
34 struct GraphRow {
35 int rid; /* The rid for the check-in */
36 int nParent; /* Number of parents */
37 int aParent[GR_MAX_PARENT]; /* Array of parents. 0 element is primary .*/
@@ -47,10 +49,11 @@
49 int aiRaiser[GR_MAX_RAIL]; /* Raisers from this node to a higher row. */
50 int bDescender; /* Raiser from bottom of graph to here. */
51 u32 mergeIn; /* Merge in from other rails */
52 int mergeOut; /* Merge out to this rail */
53 int mergeUpto; /* Draw the merge rail up to this level */
54 u32 mergeDown; /* Draw merge lines up from bottom of graph */
55
56 u32 railInUse; /* Mask of occupied rails */
57 };
58
59 /* Context while building a graph
@@ -277,27 +280,10 @@
280 }
281 hashInsert(p, pRow, 1);
282 }
283 p->mxRail = -1;
284
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285 /* Find the pChild pointer for each node.
286 **
287 ** The pChild points to the node directly above on the same rail.
288 ** The pChild must be in the same branch. Leaf nodes have a NULL
289 ** pChild.
@@ -398,22 +384,33 @@
384 */
385 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
386 for(i=1; i<pRow->nParent; i++){
387 int parentRid = pRow->aParent[i];
388 pDesc = hashFind(p, parentRid);
389 if( pDesc==0 ){
390 /* Merge from a node that is off-screen */
391 int iMrail = findFreeRail(p, pRow->idx, p->nRow, 0, 0);
392 mask = 1<<iMrail;
393 pRow->mergeIn |= mask;
394 pRow->mergeDown |= mask;
395 for(pLoop=pRow->pNext; pLoop; pLoop=pLoop->pNext){
 
396 pLoop->railInUse |= mask;
397 }
398 }else{
399 /* Merge from an on-screen node */
400 if( pDesc->mergeOut<0 ){
401 int iTarget = (pRow->iRail + pDesc->iRail)/2;
402 pDesc->mergeOut = findFreeRail(p, pRow->idx, pDesc->idx-1,0,iTarget);
403 pDesc->mergeUpto = pRow->idx;
404 mask = 1<<pDesc->mergeOut;
405 for(pLoop=pRow->pNext; pLoop && pLoop->rid!=parentRid;
406 pLoop=pLoop->pNext){
407 pLoop->railInUse |= mask;
408 }
409 }
410 pRow->mergeIn |= 1<<pDesc->mergeOut;
411 }
 
412 }
413 }
414
415 /*
416 ** Insert merge rails from primaries to duplicates.
@@ -441,7 +438,8 @@
438 */
439 p->mxRail = 0;
440 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
441 if( pRow->iRail>p->mxRail ) p->mxRail = pRow->iRail;
442 if( pRow->mergeOut>p->mxRail ) p->mxRail = pRow->mergeOut;
443 while( pRow->mergeDown>((1<<(p->mxRail+1))-1) ) p->mxRail++;
444 }
445 }
446
+5 -1
--- src/timeline.c
+++ src/timeline.c
@@ -352,17 +352,18 @@
352352
char cSep;
353353
@ <script type="text/JavaScript">
354354
@ /* <![CDATA[ */
355355
cgi_printf("var rowinfo = [\n");
356356
for(pRow=pGraph->pFirst; pRow; pRow=pRow->pNext){
357
- cgi_printf("{id:\"m%d\",bg:\"%s\",r:%d,d:%d,mo:%d,mu:%d,u:%d,au:",
357
+ cgi_printf("{id:\"m%d\",bg:\"%s\",r:%d,d:%d,mo:%d,mu:%d,md:%u,u:%d,au:",
358358
pRow->idx,
359359
pRow->zBgClr,
360360
pRow->iRail,
361361
pRow->bDescender,
362362
pRow->mergeOut,
363363
pRow->mergeUpto,
364
+ pRow->mergeDown,
364365
pRow->aiRaiser[pRow->iRail]
365366
);
366367
cSep = '[';
367368
for(i=0; i<GR_MAX_RAIL; i++){
368369
if( i==pRow->iRail ) continue;
@@ -485,10 +486,13 @@
485486
@ if( mx>p.x ){
486487
@ drawThinArrow(y0,mx,p.x+6);
487488
@ }else{
488489
@ drawThinArrow(y0,mx,p.x-5);
489490
@ }
491
+ @ if( (1<<p.mi[j])&p.md ){
492
+ @ drawThinLine(mx,y0,mx,btm);
493
+ @ }
490494
@ }
491495
@ }
492496
@ function renderGraph(){
493497
@ var canvasDiv = document.getElementById("canvas");
494498
@ while( canvasDiv.hasChildNodes() ){
495499
--- src/timeline.c
+++ src/timeline.c
@@ -352,17 +352,18 @@
352 char cSep;
353 @ <script type="text/JavaScript">
354 @ /* <![CDATA[ */
355 cgi_printf("var rowinfo = [\n");
356 for(pRow=pGraph->pFirst; pRow; pRow=pRow->pNext){
357 cgi_printf("{id:\"m%d\",bg:\"%s\",r:%d,d:%d,mo:%d,mu:%d,u:%d,au:",
358 pRow->idx,
359 pRow->zBgClr,
360 pRow->iRail,
361 pRow->bDescender,
362 pRow->mergeOut,
363 pRow->mergeUpto,
 
364 pRow->aiRaiser[pRow->iRail]
365 );
366 cSep = '[';
367 for(i=0; i<GR_MAX_RAIL; i++){
368 if( i==pRow->iRail ) continue;
@@ -485,10 +486,13 @@
485 @ if( mx>p.x ){
486 @ drawThinArrow(y0,mx,p.x+6);
487 @ }else{
488 @ drawThinArrow(y0,mx,p.x-5);
489 @ }
 
 
 
490 @ }
491 @ }
492 @ function renderGraph(){
493 @ var canvasDiv = document.getElementById("canvas");
494 @ while( canvasDiv.hasChildNodes() ){
495
--- src/timeline.c
+++ src/timeline.c
@@ -352,17 +352,18 @@
352 char cSep;
353 @ <script type="text/JavaScript">
354 @ /* <![CDATA[ */
355 cgi_printf("var rowinfo = [\n");
356 for(pRow=pGraph->pFirst; pRow; pRow=pRow->pNext){
357 cgi_printf("{id:\"m%d\",bg:\"%s\",r:%d,d:%d,mo:%d,mu:%d,md:%u,u:%d,au:",
358 pRow->idx,
359 pRow->zBgClr,
360 pRow->iRail,
361 pRow->bDescender,
362 pRow->mergeOut,
363 pRow->mergeUpto,
364 pRow->mergeDown,
365 pRow->aiRaiser[pRow->iRail]
366 );
367 cSep = '[';
368 for(i=0; i<GR_MAX_RAIL; i++){
369 if( i==pRow->iRail ) continue;
@@ -485,10 +486,13 @@
486 @ if( mx>p.x ){
487 @ drawThinArrow(y0,mx,p.x+6);
488 @ }else{
489 @ drawThinArrow(y0,mx,p.x-5);
490 @ }
491 @ if( (1<<p.mi[j])&p.md ){
492 @ drawThinLine(mx,y0,mx,btm);
493 @ }
494 @ }
495 @ }
496 @ function renderGraph(){
497 @ var canvasDiv = document.getElementById("canvas");
498 @ while( canvasDiv.hasChildNodes() ){
499

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button