Fossil SCM
In the graph, when a merge riser comes up out of a leaf on a different rail, try to shift the branch rail to be directly underneath the merge riser.
Commit
1e70f826b912a2c4e9582340bb63fdfd61bd530f54f3618b6145da42a33167aa
Parent
2bbd70da660dad9…
1 file changed
+69
-2
+69
-2
| --- src/graph.c | ||
| +++ src/graph.c | ||
| @@ -82,11 +82,12 @@ | ||
| 82 | 82 | int idx; /* Row index. Top row is smallest. */ |
| 83 | 83 | int idxTop; /* Direct descendent highest up on the graph */ |
| 84 | 84 | GraphRow *pChild; /* Child immediately above this node */ |
| 85 | 85 | u8 isDup; /* True if this is duplicate of a prior entry */ |
| 86 | 86 | u8 isLeaf; /* True if this is a leaf node */ |
| 87 | - u8 isStepParent; /* pChild is actually a step-child */ | |
| 87 | + u8 isStepParent; /* pChild is actually a step-child. The thick | |
| 88 | + ** arrow up to the child is dashed, not solid */ | |
| 88 | 89 | u8 hasNormalOutMerge; /* Is parent of at laest 1 non-cherrypick merge */ |
| 89 | 90 | u8 timeWarp; /* Child is earlier in time */ |
| 90 | 91 | u8 bDescender; /* True if riser from bottom of graph to here. */ |
| 91 | 92 | u8 selfUp; /* Space above this node but belonging */ |
| 92 | 93 | i8 iRail; /* Which rail this check-in appears on. 0-based.*/ |
| @@ -109,10 +110,12 @@ | ||
| 109 | 110 | GraphRow *pLast; /* Last row in the list. Bottom row of graph. */ |
| 110 | 111 | int nBranch; /* Number of distinct branches */ |
| 111 | 112 | char **azBranch; /* Names of the branches */ |
| 112 | 113 | int nRow; /* Number of rows */ |
| 113 | 114 | int nHash; /* Number of slots in apHash[] */ |
| 115 | + u8 hasOffsetMergeRiser; /* Merge arrow from leaf goes up on a different | |
| 116 | + ** rail that the node */ | |
| 114 | 117 | u64 mergeRail; /* Rails used for merge lines */ |
| 115 | 118 | GraphRow **apHash; /* Hash table of GraphRow objects. Key: rid */ |
| 116 | 119 | u8 aiRailMap[GR_MAX_RAIL]; /* Mapping of rails to actually columns */ |
| 117 | 120 | }; |
| 118 | 121 | |
| @@ -417,10 +420,11 @@ | ||
| 417 | 420 | pParent->mergeOut = pParent->iRail; |
| 418 | 421 | }else{ |
| 419 | 422 | /* The thin merge arrow riser is taller than the thick primary |
| 420 | 423 | ** child riser, so use separate rails. */ |
| 421 | 424 | int iTarget = pParent->iRail; |
| 425 | + if( u<0 ) p->hasOffsetMergeRiser = 1; | |
| 422 | 426 | pParent->mergeOut = findFreeRail(p, pChild->idx, pParent->idx-1, |
| 423 | 427 | iTarget, 1); |
| 424 | 428 | mask = BIT(pParent->mergeOut); |
| 425 | 429 | for(pLoop=pChild->pNext; pLoop && pLoop->rid!=pParent->rid; |
| 426 | 430 | pLoop=pLoop->pNext){ |
| @@ -469,11 +473,10 @@ | ||
| 469 | 473 | while( pRow && (n--)>0 ){ |
| 470 | 474 | pRow->railInUse |= mask; |
| 471 | 475 | pRow = pRow->pPrev; |
| 472 | 476 | } |
| 473 | 477 | } |
| 474 | - | |
| 475 | 478 | |
| 476 | 479 | /* |
| 477 | 480 | ** Compute the complete graph |
| 478 | 481 | ** |
| 479 | 482 | ** When primary or merge parents are off-screen, normally a line is drawn |
| @@ -887,10 +890,74 @@ | ||
| 887 | 890 | |
| 888 | 891 | /* |
| 889 | 892 | ** Find the maximum rail number. |
| 890 | 893 | */ |
| 891 | 894 | find_max_rail(p); |
| 895 | + | |
| 896 | + /* If a leaf node has a merge riser going up on a different rail, | |
| 897 | + ** try to move the rail of the node (and its ancestors) to be underneath | |
| 898 | + ** the merge riser. This is an optimization that improves the | |
| 899 | + ** appearance of graph but is not strictly necessary. | |
| 900 | + */ | |
| 901 | + if( nTimewarp==0 && p->hasOffsetMergeRiser ){ | |
| 902 | + for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ | |
| 903 | + GraphRow *pBottom; /* Bottom row of a branch */ | |
| 904 | + GraphRow *pRoot; /* Node off of which the branch diverges */ | |
| 905 | + int iFrom; /* Proposed to move from this rail */ | |
| 906 | + int iTo; /* Move the branch to this rail */ | |
| 907 | + | |
| 908 | + iFrom = pRow->iRail; | |
| 909 | + if( pRow->aiRiser[iFrom]>=0 ) continue; /* Not a leaf */ | |
| 910 | + if( pRow->mergeOut<0 ) continue; /* No merge riser */ | |
| 911 | + if( pRow->mergeOut==iFrom ) continue; /* Riser already aligned */ | |
| 912 | + iTo = pRow->mergeOut; | |
| 913 | + | |
| 914 | + /* Find the bottom (oldest) node in the branch */ | |
| 915 | + pBottom = 0; | |
| 916 | + for(pLoop=pRow; pLoop; pLoop=pLoop->pNext){ | |
| 917 | + if( pLoop->idxTop==pRow->idx ) pBottom = pLoop; | |
| 918 | + } | |
| 919 | + if( pBottom==0 ) continue; /* Not possible */ | |
| 920 | + | |
| 921 | + /* Verify that the rail we want to shift into is clear */ | |
| 922 | + pLoop = pBottom; | |
| 923 | + if( pLoop->pNext ) pLoop = pLoop->pNext; | |
| 924 | + if( !railIsClear(pLoop, pRow->idx+1, iTo) ){ | |
| 925 | + /* Other nodes or risers are already using the space that | |
| 926 | + ** we propose to move the pRow branch into. */ | |
| 927 | + continue; | |
| 928 | + } | |
| 929 | + | |
| 930 | + /* Find the "root" of the branch. The root is a different branch | |
| 931 | + ** from which the pRow branch emerges. There might not be a root | |
| 932 | + ** if the pRow branch started off the bottom of the screen. | |
| 933 | + */ | |
| 934 | + for(pRoot=pBottom->pNext; pRoot; pRoot=pRoot->pNext){ | |
| 935 | + if( pRoot->aiRiser[iFrom]>=0 ) break; | |
| 936 | + } | |
| 937 | + if( pRoot && pRoot->iRail==iTo ){ | |
| 938 | + /* The parent branch from which this branch emerges is on the | |
| 939 | + ** same rail as pRow. Do not shift as that would stack a child | |
| 940 | + ** branch directly above its parent. */ | |
| 941 | + continue; | |
| 942 | + } | |
| 943 | + | |
| 944 | + /* All clear. Make the translation | |
| 945 | + */ | |
| 946 | + for(pLoop=pRow; pLoop && pLoop->idx<=pBottom->idx; pLoop=pLoop->pNext){ | |
| 947 | + if( pLoop->iRail==iFrom ){ | |
| 948 | + pLoop->iRail = iTo; | |
| 949 | + pLoop->aiRiser[iTo] = pLoop->aiRiser[iFrom]; | |
| 950 | + pLoop->aiRiser[iFrom] = -1; | |
| 951 | + } | |
| 952 | + } | |
| 953 | + if( pRoot ){ | |
| 954 | + pRoot->aiRiser[iTo] = pRoot->aiRiser[iFrom]; | |
| 955 | + pRoot->aiRiser[iFrom] = -1; | |
| 956 | + } | |
| 957 | + } | |
| 958 | + } | |
| 892 | 959 | |
| 893 | 960 | /* |
| 894 | 961 | ** Compute the rail mapping that tries to put the branch named |
| 895 | 962 | ** zLeftBranch at the left margin. Other branches that merge |
| 896 | 963 | ** with zLeftBranch are to the right with merge rails in between. |
| 897 | 964 |
| --- src/graph.c | |
| +++ src/graph.c | |
| @@ -82,11 +82,12 @@ | |
| 82 | int idx; /* Row index. Top row is smallest. */ |
| 83 | int idxTop; /* Direct descendent highest up on the graph */ |
| 84 | GraphRow *pChild; /* Child immediately above this node */ |
| 85 | u8 isDup; /* True if this is duplicate of a prior entry */ |
| 86 | u8 isLeaf; /* True if this is a leaf node */ |
| 87 | u8 isStepParent; /* pChild is actually a step-child */ |
| 88 | u8 hasNormalOutMerge; /* Is parent of at laest 1 non-cherrypick merge */ |
| 89 | u8 timeWarp; /* Child is earlier in time */ |
| 90 | u8 bDescender; /* True if riser from bottom of graph to here. */ |
| 91 | u8 selfUp; /* Space above this node but belonging */ |
| 92 | i8 iRail; /* Which rail this check-in appears on. 0-based.*/ |
| @@ -109,10 +110,12 @@ | |
| 109 | GraphRow *pLast; /* Last row in the list. Bottom row of graph. */ |
| 110 | int nBranch; /* Number of distinct branches */ |
| 111 | char **azBranch; /* Names of the branches */ |
| 112 | int nRow; /* Number of rows */ |
| 113 | int nHash; /* Number of slots in apHash[] */ |
| 114 | u64 mergeRail; /* Rails used for merge lines */ |
| 115 | GraphRow **apHash; /* Hash table of GraphRow objects. Key: rid */ |
| 116 | u8 aiRailMap[GR_MAX_RAIL]; /* Mapping of rails to actually columns */ |
| 117 | }; |
| 118 | |
| @@ -417,10 +420,11 @@ | |
| 417 | pParent->mergeOut = pParent->iRail; |
| 418 | }else{ |
| 419 | /* The thin merge arrow riser is taller than the thick primary |
| 420 | ** child riser, so use separate rails. */ |
| 421 | int iTarget = pParent->iRail; |
| 422 | pParent->mergeOut = findFreeRail(p, pChild->idx, pParent->idx-1, |
| 423 | iTarget, 1); |
| 424 | mask = BIT(pParent->mergeOut); |
| 425 | for(pLoop=pChild->pNext; pLoop && pLoop->rid!=pParent->rid; |
| 426 | pLoop=pLoop->pNext){ |
| @@ -469,11 +473,10 @@ | |
| 469 | while( pRow && (n--)>0 ){ |
| 470 | pRow->railInUse |= mask; |
| 471 | pRow = pRow->pPrev; |
| 472 | } |
| 473 | } |
| 474 | |
| 475 | |
| 476 | /* |
| 477 | ** Compute the complete graph |
| 478 | ** |
| 479 | ** When primary or merge parents are off-screen, normally a line is drawn |
| @@ -887,10 +890,74 @@ | |
| 887 | |
| 888 | /* |
| 889 | ** Find the maximum rail number. |
| 890 | */ |
| 891 | find_max_rail(p); |
| 892 | |
| 893 | /* |
| 894 | ** Compute the rail mapping that tries to put the branch named |
| 895 | ** zLeftBranch at the left margin. Other branches that merge |
| 896 | ** with zLeftBranch are to the right with merge rails in between. |
| 897 |
| --- src/graph.c | |
| +++ src/graph.c | |
| @@ -82,11 +82,12 @@ | |
| 82 | int idx; /* Row index. Top row is smallest. */ |
| 83 | int idxTop; /* Direct descendent highest up on the graph */ |
| 84 | GraphRow *pChild; /* Child immediately above this node */ |
| 85 | u8 isDup; /* True if this is duplicate of a prior entry */ |
| 86 | u8 isLeaf; /* True if this is a leaf node */ |
| 87 | u8 isStepParent; /* pChild is actually a step-child. The thick |
| 88 | ** arrow up to the child is dashed, not solid */ |
| 89 | u8 hasNormalOutMerge; /* Is parent of at laest 1 non-cherrypick merge */ |
| 90 | u8 timeWarp; /* Child is earlier in time */ |
| 91 | u8 bDescender; /* True if riser from bottom of graph to here. */ |
| 92 | u8 selfUp; /* Space above this node but belonging */ |
| 93 | i8 iRail; /* Which rail this check-in appears on. 0-based.*/ |
| @@ -109,10 +110,12 @@ | |
| 110 | GraphRow *pLast; /* Last row in the list. Bottom row of graph. */ |
| 111 | int nBranch; /* Number of distinct branches */ |
| 112 | char **azBranch; /* Names of the branches */ |
| 113 | int nRow; /* Number of rows */ |
| 114 | int nHash; /* Number of slots in apHash[] */ |
| 115 | u8 hasOffsetMergeRiser; /* Merge arrow from leaf goes up on a different |
| 116 | ** rail that the node */ |
| 117 | u64 mergeRail; /* Rails used for merge lines */ |
| 118 | GraphRow **apHash; /* Hash table of GraphRow objects. Key: rid */ |
| 119 | u8 aiRailMap[GR_MAX_RAIL]; /* Mapping of rails to actually columns */ |
| 120 | }; |
| 121 | |
| @@ -417,10 +420,11 @@ | |
| 420 | pParent->mergeOut = pParent->iRail; |
| 421 | }else{ |
| 422 | /* The thin merge arrow riser is taller than the thick primary |
| 423 | ** child riser, so use separate rails. */ |
| 424 | int iTarget = pParent->iRail; |
| 425 | if( u<0 ) p->hasOffsetMergeRiser = 1; |
| 426 | pParent->mergeOut = findFreeRail(p, pChild->idx, pParent->idx-1, |
| 427 | iTarget, 1); |
| 428 | mask = BIT(pParent->mergeOut); |
| 429 | for(pLoop=pChild->pNext; pLoop && pLoop->rid!=pParent->rid; |
| 430 | pLoop=pLoop->pNext){ |
| @@ -469,11 +473,10 @@ | |
| 473 | while( pRow && (n--)>0 ){ |
| 474 | pRow->railInUse |= mask; |
| 475 | pRow = pRow->pPrev; |
| 476 | } |
| 477 | } |
| 478 | |
| 479 | /* |
| 480 | ** Compute the complete graph |
| 481 | ** |
| 482 | ** When primary or merge parents are off-screen, normally a line is drawn |
| @@ -887,10 +890,74 @@ | |
| 890 | |
| 891 | /* |
| 892 | ** Find the maximum rail number. |
| 893 | */ |
| 894 | find_max_rail(p); |
| 895 | |
| 896 | /* If a leaf node has a merge riser going up on a different rail, |
| 897 | ** try to move the rail of the node (and its ancestors) to be underneath |
| 898 | ** the merge riser. This is an optimization that improves the |
| 899 | ** appearance of graph but is not strictly necessary. |
| 900 | */ |
| 901 | if( nTimewarp==0 && p->hasOffsetMergeRiser ){ |
| 902 | for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ |
| 903 | GraphRow *pBottom; /* Bottom row of a branch */ |
| 904 | GraphRow *pRoot; /* Node off of which the branch diverges */ |
| 905 | int iFrom; /* Proposed to move from this rail */ |
| 906 | int iTo; /* Move the branch to this rail */ |
| 907 | |
| 908 | iFrom = pRow->iRail; |
| 909 | if( pRow->aiRiser[iFrom]>=0 ) continue; /* Not a leaf */ |
| 910 | if( pRow->mergeOut<0 ) continue; /* No merge riser */ |
| 911 | if( pRow->mergeOut==iFrom ) continue; /* Riser already aligned */ |
| 912 | iTo = pRow->mergeOut; |
| 913 | |
| 914 | /* Find the bottom (oldest) node in the branch */ |
| 915 | pBottom = 0; |
| 916 | for(pLoop=pRow; pLoop; pLoop=pLoop->pNext){ |
| 917 | if( pLoop->idxTop==pRow->idx ) pBottom = pLoop; |
| 918 | } |
| 919 | if( pBottom==0 ) continue; /* Not possible */ |
| 920 | |
| 921 | /* Verify that the rail we want to shift into is clear */ |
| 922 | pLoop = pBottom; |
| 923 | if( pLoop->pNext ) pLoop = pLoop->pNext; |
| 924 | if( !railIsClear(pLoop, pRow->idx+1, iTo) ){ |
| 925 | /* Other nodes or risers are already using the space that |
| 926 | ** we propose to move the pRow branch into. */ |
| 927 | continue; |
| 928 | } |
| 929 | |
| 930 | /* Find the "root" of the branch. The root is a different branch |
| 931 | ** from which the pRow branch emerges. There might not be a root |
| 932 | ** if the pRow branch started off the bottom of the screen. |
| 933 | */ |
| 934 | for(pRoot=pBottom->pNext; pRoot; pRoot=pRoot->pNext){ |
| 935 | if( pRoot->aiRiser[iFrom]>=0 ) break; |
| 936 | } |
| 937 | if( pRoot && pRoot->iRail==iTo ){ |
| 938 | /* The parent branch from which this branch emerges is on the |
| 939 | ** same rail as pRow. Do not shift as that would stack a child |
| 940 | ** branch directly above its parent. */ |
| 941 | continue; |
| 942 | } |
| 943 | |
| 944 | /* All clear. Make the translation |
| 945 | */ |
| 946 | for(pLoop=pRow; pLoop && pLoop->idx<=pBottom->idx; pLoop=pLoop->pNext){ |
| 947 | if( pLoop->iRail==iFrom ){ |
| 948 | pLoop->iRail = iTo; |
| 949 | pLoop->aiRiser[iTo] = pLoop->aiRiser[iFrom]; |
| 950 | pLoop->aiRiser[iFrom] = -1; |
| 951 | } |
| 952 | } |
| 953 | if( pRoot ){ |
| 954 | pRoot->aiRiser[iTo] = pRoot->aiRiser[iFrom]; |
| 955 | pRoot->aiRiser[iFrom] = -1; |
| 956 | } |
| 957 | } |
| 958 | } |
| 959 | |
| 960 | /* |
| 961 | ** Compute the rail mapping that tries to put the branch named |
| 962 | ** zLeftBranch at the left margin. Other branches that merge |
| 963 | ** with zLeftBranch are to the right with merge rails in between. |
| 964 |