subcommanderblog.wordpress.com

Subcommander Development Blog

Archive for June 2008

submerge

leave a comment »

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);

...

Above 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 :)

submerge with a curved connection between left and right file

MacOSX: submerge with a curved connection between left and right file

Written by hauner

Sunday, 22 June, 2008 at 11:25

Posted in submerge

Tagged with