submerge
I always liked the way the FileMerge utility on MacOSX connects a
left and right file difference with a curved connection. I played with
this a couple of years ago but since Qt3 did not support antialiasing
out of the box I dropped it again. Without antialiasing a curved line
does not look very good.
After spending some time improving the redrawing issues in submerge
I mentioned in Qt4 (unfortunately there are still
a few pixel glitches, but it is a lot better than before) I
implemented a curved connection with antialiasing. A reward for fixing
most of the redrawing issues ;-)
Since Qt4 supports antialiasing simply by setting a render hint on
the QPainter class it was quite easy to implement this time. Most work
was to get access to proper size information for a single difference
block. That is how many lines in the left file (OriginalLength)
and how many lines in the right file (ModifiedLength)create a
difference block and have to be connected. Luckily this information was
already calculated by the diff code and I only had to add it to the
existing BlockInfo info class.
The drawing code then goes like this:
...
Line lline = _left->getLine(curLine);
Line rline = _right->getLine(curLine);
const BlockInfo& lb = _model->getInfo( lline.getBlockNr() ).getBlockInfo();
...
svn::Offset sl = lb.getStart() + lb.getOriginalLength();
svn::Offset sr = lb.getStart() + lb.getModifiedLength();
...
int top = tpc.getLineY((int)lb.getStart());
int botLeft = tpc.getLineY((int)sl);
int botRight = tpc.getLineY((int)sr);
QPainterPath path;
path.moveTo(0,top);
path.lineTo(0,botLeft);
path.cubicTo(lnDefWidth-5,botLeft, 5,botRight, lnDefWidth,botRight);
path.lineTo(lnDefWidth,top);
path.lineTo(0,top);
DiffInfo& info = _model->getInfo(block);
QColor lcolor = getBgColor( lline.getType(), info.getMergeType(), true );
QColor rcolor = getBgColor( rline.getType(), info.getMergeType(), false );
QLinearGradient gradient(0,0,lnDefWidth,0);
gradient.setColorAt(0, lcolor );
gradient.setColorAt(1, rcolor );
QBrush brush(gradient);
pp.setRenderHint(QPainter::Antialiasing);
pp.setPen(Qt::NoPen);
pp.setBrush(brush);
pp.drawPath(path);
...
On the left you can see the most interesting parts of the
code. I have omitted the code that takes care of painting the
connection only once for every block.
If the current line is part of a difference block I calculate
the bottom y pixel position for the left block part based on the
OriginalLength and the right block part based on
ModifiedLength.
Then I create a cubic PainterPath that
describes the curved connection. lnDefWidth is a constant
value the represents the width of the glue area between the left
and right file.
Next I create a gradient between the background colors of the
left and the right file to get a smooth transition if the colors
are different (on merging a selected left or right block gets
a different color to give feedback which file was choosen for the
merged file).
Finally the connection gets drawn with antialiasing to get
a smooth curve.
Below is a submerge screenshot showing what it looks like. The two
files are unrelated to get a lot of differences :)
MacOSX: submerge with a curved connection between left and right file
22nd June 2008 |
Comment