Fossil SCM

Improvements to the display of the "Context" graph on check-in /info pages.

drh 2019-05-14 13:47 trunk
Commit 01d8bf97e206fc8eeae4c59e6046a9ae148d6ba8a3e56a17782904ab84199869
--- src/default_css.txt
+++ src/default_css.txt
@@ -189,10 +189,16 @@
189189
border-left: 7px solid #600000;
190190
}
191191
.tl-line.warp {
192192
background: #600000;
193193
}
194
+.tl-line.dotted {
195
+ width: 0px;
196
+ border-top: 0px dotted #888;
197
+ border-left: 2px dotted #888;
198
+ background: rgba(255,255,255,0);
199
+}
194200
span.tagDsp {
195201
font-weight: bold;
196202
}
197203
span.wikiError {
198204
font-weight: bold;
199205
--- src/default_css.txt
+++ src/default_css.txt
@@ -189,10 +189,16 @@
189 border-left: 7px solid #600000;
190 }
191 .tl-line.warp {
192 background: #600000;
193 }
 
 
 
 
 
 
194 span.tagDsp {
195 font-weight: bold;
196 }
197 span.wikiError {
198 font-weight: bold;
199
--- src/default_css.txt
+++ src/default_css.txt
@@ -189,10 +189,16 @@
189 border-left: 7px solid #600000;
190 }
191 .tl-line.warp {
192 background: #600000;
193 }
194 .tl-line.dotted {
195 width: 0px;
196 border-top: 0px dotted #888;
197 border-left: 2px dotted #888;
198 background: rgba(255,255,255,0);
199 }
200 span.tagDsp {
201 font-weight: bold;
202 }
203 span.wikiError {
204 font-weight: bold;
205
+23 -2
--- src/graph.c
+++ src/graph.c
@@ -49,10 +49,11 @@
4949
int idx; /* Row index. First is 1. 0 used for "none" */
5050
int idxTop; /* Direct descendent highest up on the graph */
5151
GraphRow *pChild; /* Child immediately above this node */
5252
u8 isDup; /* True if this is duplicate of a prior entry */
5353
u8 isLeaf; /* True if this is a leaf node */
54
+ u8 isStepParent; /* pChild is actually a step-child */
5455
u8 hasNormalOutMerge; /* Is parent of at laest 1 non-cherrypick merge */
5556
u8 timeWarp; /* Child is earlier in time */
5657
u8 bDescender; /* True if riser from bottom of graph to here. */
5758
i8 iRail; /* Which rail this check-in appears on. 0-based.*/
5859
i8 mergeOut; /* Merge out to this rail. -1 if no merge-out */
@@ -69,12 +70,12 @@
6970
/* Context while building a graph
7071
*/
7172
struct GraphContext {
7273
int nErr; /* Number of errors encountered */
7374
int mxRail; /* Number of rails required to render the graph */
74
- GraphRow *pFirst; /* First row in the list */
75
- GraphRow *pLast; /* Last row in the list */
75
+ GraphRow *pFirst; /* First row in the list. Top row of graph. */
76
+ GraphRow *pLast; /* Last row in the list. Bottom row of graph. */
7677
int nBranch; /* Number of distinct branches */
7778
char **azBranch; /* Names of the branches */
7879
int nRow; /* Number of rows */
7980
int nHash; /* Number of slots in apHash[] */
8081
GraphRow **apHash; /* Hash table of GraphRow objects. Key: rid */
@@ -477,10 +478,30 @@
477478
if( pRow->idxTop < pParent->idxTop ){
478479
pParent->pChild = pRow;
479480
pParent->idxTop = pRow->idxTop;
480481
}
481482
}
483
+
484
+ /* If a node has no pChild, and there is a later node (a node higher
485
+ ** up on the graph) in the same branch that has no parent, then make
486
+ ** the lower node a step-child of the upper node.
487
+ */
488
+ for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
489
+ if( pRow->pChild ) continue;
490
+ for(pLoop=pRow->pPrev; pLoop; pLoop=pLoop->pPrev){
491
+ if( pLoop->nParent>0
492
+ && pLoop->zBranch==pRow->zBranch
493
+ && hashFind(p,pLoop->aParent[0])==0
494
+ ){
495
+ pRow->pChild = pLoop;
496
+ pRow->idxTop = pLoop->idxTop;
497
+ pRow->isStepParent = 1;
498
+ pLoop->aParent[0] = pRow->rid;
499
+ break;
500
+ }
501
+ }
502
+ }
482503
483504
/* Identify rows where the primary parent is off screen. Assign
484505
** each to a rail and draw descenders to the bottom of the screen.
485506
**
486507
** Strive to put the "trunk" branch on far left.
487508
--- src/graph.c
+++ src/graph.c
@@ -49,10 +49,11 @@
49 int idx; /* Row index. First is 1. 0 used for "none" */
50 int idxTop; /* Direct descendent highest up on the graph */
51 GraphRow *pChild; /* Child immediately above this node */
52 u8 isDup; /* True if this is duplicate of a prior entry */
53 u8 isLeaf; /* True if this is a leaf node */
 
54 u8 hasNormalOutMerge; /* Is parent of at laest 1 non-cherrypick merge */
55 u8 timeWarp; /* Child is earlier in time */
56 u8 bDescender; /* True if riser from bottom of graph to here. */
57 i8 iRail; /* Which rail this check-in appears on. 0-based.*/
58 i8 mergeOut; /* Merge out to this rail. -1 if no merge-out */
@@ -69,12 +70,12 @@
69 /* Context while building a graph
70 */
71 struct GraphContext {
72 int nErr; /* Number of errors encountered */
73 int mxRail; /* Number of rails required to render the graph */
74 GraphRow *pFirst; /* First row in the list */
75 GraphRow *pLast; /* Last row in the list */
76 int nBranch; /* Number of distinct branches */
77 char **azBranch; /* Names of the branches */
78 int nRow; /* Number of rows */
79 int nHash; /* Number of slots in apHash[] */
80 GraphRow **apHash; /* Hash table of GraphRow objects. Key: rid */
@@ -477,10 +478,30 @@
477 if( pRow->idxTop < pParent->idxTop ){
478 pParent->pChild = pRow;
479 pParent->idxTop = pRow->idxTop;
480 }
481 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
482
483 /* Identify rows where the primary parent is off screen. Assign
484 ** each to a rail and draw descenders to the bottom of the screen.
485 **
486 ** Strive to put the "trunk" branch on far left.
487
--- src/graph.c
+++ src/graph.c
@@ -49,10 +49,11 @@
49 int idx; /* Row index. First is 1. 0 used for "none" */
50 int idxTop; /* Direct descendent highest up on the graph */
51 GraphRow *pChild; /* Child immediately above this node */
52 u8 isDup; /* True if this is duplicate of a prior entry */
53 u8 isLeaf; /* True if this is a leaf node */
54 u8 isStepParent; /* pChild is actually a step-child */
55 u8 hasNormalOutMerge; /* Is parent of at laest 1 non-cherrypick merge */
56 u8 timeWarp; /* Child is earlier in time */
57 u8 bDescender; /* True if riser from bottom of graph to here. */
58 i8 iRail; /* Which rail this check-in appears on. 0-based.*/
59 i8 mergeOut; /* Merge out to this rail. -1 if no merge-out */
@@ -69,12 +70,12 @@
70 /* Context while building a graph
71 */
72 struct GraphContext {
73 int nErr; /* Number of errors encountered */
74 int mxRail; /* Number of rails required to render the graph */
75 GraphRow *pFirst; /* First row in the list. Top row of graph. */
76 GraphRow *pLast; /* Last row in the list. Bottom row of graph. */
77 int nBranch; /* Number of distinct branches */
78 char **azBranch; /* Names of the branches */
79 int nRow; /* Number of rows */
80 int nHash; /* Number of slots in apHash[] */
81 GraphRow **apHash; /* Hash table of GraphRow objects. Key: rid */
@@ -477,10 +478,30 @@
478 if( pRow->idxTop < pParent->idxTop ){
479 pParent->pChild = pRow;
480 pParent->idxTop = pRow->idxTop;
481 }
482 }
483
484 /* If a node has no pChild, and there is a later node (a node higher
485 ** up on the graph) in the same branch that has no parent, then make
486 ** the lower node a step-child of the upper node.
487 */
488 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
489 if( pRow->pChild ) continue;
490 for(pLoop=pRow->pPrev; pLoop; pLoop=pLoop->pPrev){
491 if( pLoop->nParent>0
492 && pLoop->zBranch==pRow->zBranch
493 && hashFind(p,pLoop->aParent[0])==0
494 ){
495 pRow->pChild = pLoop;
496 pRow->idxTop = pLoop->idxTop;
497 pRow->isStepParent = 1;
498 pLoop->aParent[0] = pRow->rid;
499 break;
500 }
501 }
502 }
503
504 /* Identify rows where the primary parent is off screen. Assign
505 ** each to a rail and draw descenders to the bottom of the screen.
506 **
507 ** Strive to put the "trunk" branch on far left.
508
+9 -1
--- src/graph.js
+++ src/graph.js
@@ -92,11 +92,11 @@
9292
9393
var elems = {};
9494
var elemClasses = [
9595
"rail", "mergeoffset", "node", "arrow u", "arrow u sm", "line",
9696
"arrow merge r", "line merge", "arrow warp", "line warp",
97
- "line cherrypick"
97
+ "line cherrypick", "line dotted"
9898
];
9999
for( var i=0; i<elemClasses.length; i++ ){
100100
var cls = elemClasses[i];
101101
var elem = document.createElement("div");
102102
elem.className = "tl-" + cls;
@@ -115,10 +115,11 @@
115115
mArrow = elems.arrow_merge_r;
116116
mLine = elems.line_merge;
117117
cpLine = elems.line_cherrypick;
118118
wArrow = elems.arrow_warp;
119119
wLine = elems.line_warp;
120
+ dotLine = elems.line_dotted;
120121
121122
var minRailPitch = Math.ceil((node.w+line.w)/2 + mArrow.w + 1);
122123
if( window.innerWidth<400 ){
123124
railPitch = minRailPitch;
124125
}else{
@@ -196,10 +197,16 @@
196197
drawLine(line,color,x,y0,null,y1);
197198
x = to.x + (node.w-arw.w)/2;
198199
var n = drawBox(arw.cls,null,x,y);
199200
if(color) n.style.borderBottomColor = color;
200201
}
202
+ function drawUpDotted(from,to,color){
203
+ var x = to.x + (node.w-line.w)/2;
204
+ var y0 = from.y + node.h/2;
205
+ var y1 = Math.ceil(to.y + node.h);
206
+ drawLine(dotLine,color,x,y0,null,y1);
207
+ }
201208
/* Draw thin horizontal or vertical lines representing merges */
202209
function drawMergeLine(x0,y0,x1,y1){
203210
drawLine(mLine,null,x0,y0,x1,y1);
204211
}
205212
function drawCherrypickLine(x0,y0,x1,y1){
@@ -236,10 +243,11 @@
236243
e = document.getElementById("md"+p.id);
237244
if(e) e.style.backgroundColor = p.bg;
238245
}
239246
if( p.r<0 ) return;
240247
if( p.u>0 ) drawUpArrow(p,tx.rowinfo[p.u-tx.iTopRow],p.fg);
248
+ if( p.sb>0 ) drawUpDotted(p,tx.rowinfo[p.sb-tx.iTopRow],p.fg);
241249
var cls = node.cls;
242250
if( p.hasOwnProperty('mi') && p.mi.length ) cls += " merge";
243251
if( p.f&1 ) cls += " leaf";
244252
var n = drawBox(cls,p.bg,p.x,p.y);
245253
n.id = "tln"+p.id;
246254
--- src/graph.js
+++ src/graph.js
@@ -92,11 +92,11 @@
92
93 var elems = {};
94 var elemClasses = [
95 "rail", "mergeoffset", "node", "arrow u", "arrow u sm", "line",
96 "arrow merge r", "line merge", "arrow warp", "line warp",
97 "line cherrypick"
98 ];
99 for( var i=0; i<elemClasses.length; i++ ){
100 var cls = elemClasses[i];
101 var elem = document.createElement("div");
102 elem.className = "tl-" + cls;
@@ -115,10 +115,11 @@
115 mArrow = elems.arrow_merge_r;
116 mLine = elems.line_merge;
117 cpLine = elems.line_cherrypick;
118 wArrow = elems.arrow_warp;
119 wLine = elems.line_warp;
 
120
121 var minRailPitch = Math.ceil((node.w+line.w)/2 + mArrow.w + 1);
122 if( window.innerWidth<400 ){
123 railPitch = minRailPitch;
124 }else{
@@ -196,10 +197,16 @@
196 drawLine(line,color,x,y0,null,y1);
197 x = to.x + (node.w-arw.w)/2;
198 var n = drawBox(arw.cls,null,x,y);
199 if(color) n.style.borderBottomColor = color;
200 }
 
 
 
 
 
 
201 /* Draw thin horizontal or vertical lines representing merges */
202 function drawMergeLine(x0,y0,x1,y1){
203 drawLine(mLine,null,x0,y0,x1,y1);
204 }
205 function drawCherrypickLine(x0,y0,x1,y1){
@@ -236,10 +243,11 @@
236 e = document.getElementById("md"+p.id);
237 if(e) e.style.backgroundColor = p.bg;
238 }
239 if( p.r<0 ) return;
240 if( p.u>0 ) drawUpArrow(p,tx.rowinfo[p.u-tx.iTopRow],p.fg);
 
241 var cls = node.cls;
242 if( p.hasOwnProperty('mi') && p.mi.length ) cls += " merge";
243 if( p.f&1 ) cls += " leaf";
244 var n = drawBox(cls,p.bg,p.x,p.y);
245 n.id = "tln"+p.id;
246
--- src/graph.js
+++ src/graph.js
@@ -92,11 +92,11 @@
92
93 var elems = {};
94 var elemClasses = [
95 "rail", "mergeoffset", "node", "arrow u", "arrow u sm", "line",
96 "arrow merge r", "line merge", "arrow warp", "line warp",
97 "line cherrypick", "line dotted"
98 ];
99 for( var i=0; i<elemClasses.length; i++ ){
100 var cls = elemClasses[i];
101 var elem = document.createElement("div");
102 elem.className = "tl-" + cls;
@@ -115,10 +115,11 @@
115 mArrow = elems.arrow_merge_r;
116 mLine = elems.line_merge;
117 cpLine = elems.line_cherrypick;
118 wArrow = elems.arrow_warp;
119 wLine = elems.line_warp;
120 dotLine = elems.line_dotted;
121
122 var minRailPitch = Math.ceil((node.w+line.w)/2 + mArrow.w + 1);
123 if( window.innerWidth<400 ){
124 railPitch = minRailPitch;
125 }else{
@@ -196,10 +197,16 @@
197 drawLine(line,color,x,y0,null,y1);
198 x = to.x + (node.w-arw.w)/2;
199 var n = drawBox(arw.cls,null,x,y);
200 if(color) n.style.borderBottomColor = color;
201 }
202 function drawUpDotted(from,to,color){
203 var x = to.x + (node.w-line.w)/2;
204 var y0 = from.y + node.h/2;
205 var y1 = Math.ceil(to.y + node.h);
206 drawLine(dotLine,color,x,y0,null,y1);
207 }
208 /* Draw thin horizontal or vertical lines representing merges */
209 function drawMergeLine(x0,y0,x1,y1){
210 drawLine(mLine,null,x0,y0,x1,y1);
211 }
212 function drawCherrypickLine(x0,y0,x1,y1){
@@ -236,10 +243,11 @@
243 e = document.getElementById("md"+p.id);
244 if(e) e.style.backgroundColor = p.bg;
245 }
246 if( p.r<0 ) return;
247 if( p.u>0 ) drawUpArrow(p,tx.rowinfo[p.u-tx.iTopRow],p.fg);
248 if( p.sb>0 ) drawUpDotted(p,tx.rowinfo[p.sb-tx.iTopRow],p.fg);
249 var cls = node.cls;
250 if( p.hasOwnProperty('mi') && p.mi.length ) cls += " merge";
251 if( p.f&1 ) cls += " leaf";
252 var n = drawBox(cls,p.bg,p.x,p.y);
253 n.id = "tln"+p.id;
254
+1 -2
--- src/info.c
+++ src/info.c
@@ -281,12 +281,11 @@
281281
}
282282
}
283283
blob_append_sql(&sql, " AND event.objid IN ok ORDER BY mtime DESC");
284284
db_prepare(&q, "%s", blob_sql_text(&sql));
285285
www_print_timeline(&q,
286
- TIMELINE_DISJOINT
287
- |TIMELINE_GRAPH
286
+ TIMELINE_GRAPH
288287
|TIMELINE_NOSCROLL
289288
|TIMELINE_CHPICK,
290289
0, 0, rid, 0);
291290
db_finalize(&q);
292291
}
293292
--- src/info.c
+++ src/info.c
@@ -281,12 +281,11 @@
281 }
282 }
283 blob_append_sql(&sql, " AND event.objid IN ok ORDER BY mtime DESC");
284 db_prepare(&q, "%s", blob_sql_text(&sql));
285 www_print_timeline(&q,
286 TIMELINE_DISJOINT
287 |TIMELINE_GRAPH
288 |TIMELINE_NOSCROLL
289 |TIMELINE_CHPICK,
290 0, 0, rid, 0);
291 db_finalize(&q);
292 }
293
--- src/info.c
+++ src/info.c
@@ -281,12 +281,11 @@
281 }
282 }
283 blob_append_sql(&sql, " AND event.objid IN ok ORDER BY mtime DESC");
284 db_prepare(&q, "%s", blob_sql_text(&sql));
285 www_print_timeline(&q,
286 TIMELINE_GRAPH
 
287 |TIMELINE_NOSCROLL
288 |TIMELINE_CHPICK,
289 0, 0, rid, 0);
290 db_finalize(&q);
291 }
292
+9 -1
--- src/timeline.c
+++ src/timeline.c
@@ -879,10 +879,14 @@
879879
** cu: Extend the mu merge arrow up to this row as a cherrypick
880880
** merge line, if this value exists.
881881
** u: Draw a thick child-line out of the top of this node and up to
882882
** the node with an id equal to this value. 0 if it is straight to
883883
** the top of the page, -1 if there is no thick-line riser.
884
+ ** sb: Draw a dotted child-line out of the top of this node up to the
885
+ ** node with the id equal to the value. This is like "u" except
886
+ ** that the line is dotted instead of solid and has no arrow.
887
+ ** Mnemonic: "Same Branch".
884888
** f: 0x01: a leaf node.
885889
** au: An array of integers that define thick-line risers for branches.
886890
** The integers are in pairs. For each pair, the first integer is
887891
** is the rail on which the riser should run and the second integer
888892
** is the id of the node upto which the riser should run. If there
@@ -911,11 +915,15 @@
911915
cgi_printf("\"mu\":%d,", pRow->mergeUpto);
912916
if( pRow->cherrypickUpto>0 && pRow->cherrypickUpto<pRow->mergeUpto ){
913917
cgi_printf("\"cu\":%d,", pRow->cherrypickUpto);
914918
}
915919
}
916
- cgi_printf("\"u\":%d,", pRow->aiRiser[pRow->iRail]);
920
+ if( pRow->isStepParent ){
921
+ cgi_printf("\"sb\":%d,", pRow->aiRiser[pRow->iRail]);
922
+ }else{
923
+ cgi_printf("\"u\":%d,", pRow->aiRiser[pRow->iRail]);
924
+ }
917925
k = 0;
918926
if( pRow->isLeaf ) k |= 1;
919927
cgi_printf("\"f\":%d,",k);
920928
for(i=k=0; i<GR_MAX_RAIL; i++){
921929
if( i==pRow->iRail ) continue;
922930
--- src/timeline.c
+++ src/timeline.c
@@ -879,10 +879,14 @@
879 ** cu: Extend the mu merge arrow up to this row as a cherrypick
880 ** merge line, if this value exists.
881 ** u: Draw a thick child-line out of the top of this node and up to
882 ** the node with an id equal to this value. 0 if it is straight to
883 ** the top of the page, -1 if there is no thick-line riser.
 
 
 
 
884 ** f: 0x01: a leaf node.
885 ** au: An array of integers that define thick-line risers for branches.
886 ** The integers are in pairs. For each pair, the first integer is
887 ** is the rail on which the riser should run and the second integer
888 ** is the id of the node upto which the riser should run. If there
@@ -911,11 +915,15 @@
911 cgi_printf("\"mu\":%d,", pRow->mergeUpto);
912 if( pRow->cherrypickUpto>0 && pRow->cherrypickUpto<pRow->mergeUpto ){
913 cgi_printf("\"cu\":%d,", pRow->cherrypickUpto);
914 }
915 }
916 cgi_printf("\"u\":%d,", pRow->aiRiser[pRow->iRail]);
 
 
 
 
917 k = 0;
918 if( pRow->isLeaf ) k |= 1;
919 cgi_printf("\"f\":%d,",k);
920 for(i=k=0; i<GR_MAX_RAIL; i++){
921 if( i==pRow->iRail ) continue;
922
--- src/timeline.c
+++ src/timeline.c
@@ -879,10 +879,14 @@
879 ** cu: Extend the mu merge arrow up to this row as a cherrypick
880 ** merge line, if this value exists.
881 ** u: Draw a thick child-line out of the top of this node and up to
882 ** the node with an id equal to this value. 0 if it is straight to
883 ** the top of the page, -1 if there is no thick-line riser.
884 ** sb: Draw a dotted child-line out of the top of this node up to the
885 ** node with the id equal to the value. This is like "u" except
886 ** that the line is dotted instead of solid and has no arrow.
887 ** Mnemonic: "Same Branch".
888 ** f: 0x01: a leaf node.
889 ** au: An array of integers that define thick-line risers for branches.
890 ** The integers are in pairs. For each pair, the first integer is
891 ** is the rail on which the riser should run and the second integer
892 ** is the id of the node upto which the riser should run. If there
@@ -911,11 +915,15 @@
915 cgi_printf("\"mu\":%d,", pRow->mergeUpto);
916 if( pRow->cherrypickUpto>0 && pRow->cherrypickUpto<pRow->mergeUpto ){
917 cgi_printf("\"cu\":%d,", pRow->cherrypickUpto);
918 }
919 }
920 if( pRow->isStepParent ){
921 cgi_printf("\"sb\":%d,", pRow->aiRiser[pRow->iRail]);
922 }else{
923 cgi_printf("\"u\":%d,", pRow->aiRiser[pRow->iRail]);
924 }
925 k = 0;
926 if( pRow->isLeaf ) k |= 1;
927 cgi_printf("\"f\":%d,",k);
928 for(i=k=0; i<GR_MAX_RAIL; i++){
929 if( i==pRow->iRail ) continue;
930

Keyboard Shortcuts

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