#include "MergeWidget.h" #include <QFileDialog> #include <QImageReader> #include <QMessageBox> #include <QPainter> #include <QWhatsThis> #include "util.h" MergeWidget::MergeWidget( char* b, char* theirs, char* yours ) :BaseWidget( theirs, yours ) { base = QImage( b ); if ( base.size() != leg1.size() ) { base = base.scaled( leg1.size() ); } resultFormat = QImageReader::imageFormat( yours ); merge = QImage( base.size(), QImage::Format_ARGB32_Premultiplied ); base_theirs_t = base_yours_t = conflicts_t = -1; base_theirs = QBitmap( base.size() ); base_yours = QBitmap( base.size() ); conflicts = QBitmap( base.size() ); main = editor = new MergeEditor; main_l->addWidget( main ); editor->setImage( &merge ); editor->setTheirs( &leg1 ); editor->setYours( &leg2 ); slider->setRange( 0, 255 ); slider->setValue( 127 ); slider->setSingleStep( 16 ); slider->setPageStep( 255 ); slider->setEnabled( false ); connect( slider, SIGNAL( valueChanged(int) ), editor, SLOT( setBlend(int) ) ); editor->setBlend( 127 ); connect( editor, SIGNAL( imageEdited() ), this, SLOT( imageEdited() ) ); p1->setPalette( QPalette( QColor( 0, 0, 100 ) ) ); p2->setPalette( QPalette( QColor( 0, 100, 0 ) ) ); p1->setVeilColor( QColor( 0, 0, 100 ) ); p2->setVeilColor( QColor( 0, 100, 0 ) ); p1->setFrameStyle( QFrame::Box ); p2->setFrameStyle( QFrame::Box ); } MergeWidget::~MergeWidget(void) { } void MergeWidget::autoMerge() { //Get all the diffs calculated. freshenConflicts(); QPainter p( &merge ); p.setCompositionMode( QPainter::CompositionMode_Source ); //Start with the yours file. p.drawImage( 0, 0, leg2 ); //Overlay all of the theirs diffs. QRegion all( merge.rect() ); QRegion t( base_theirs ); t = all.subtract( t ); p.setClipRegion( t ); p.drawImage( 0, 0, leg1 ); //Overlay the conflicts. QRegion c( conflicts ); c = all.subtract( c ); p.setClipRegion( c ); p.fillRect( merge.rect(), conflict ); editor->update(); } void MergeWidget::setTheirsMask( bool on ) { if ( base_theirs_t != tolerance ) imageDiff( base, leg1, &base_theirs, tolerance ); main->setMask( &base_theirs ); main->setMaskEnabled( on ); } void MergeWidget::setYoursMask( bool on ) { if ( base_yours_t != tolerance ) imageDiff( base, leg2, &base_yours, tolerance ); main->setMask( &base_yours ); main->setMaskEnabled( on ); } void MergeWidget::setConflictMask( bool on ) { freshenConflicts(); main->setMask( &conflicts ); main->setMaskEnabled( on ); } void MergeWidget::setBrushSize( int px ) { editor->setBrushSize( px ); } void MergeWidget::setEraserSize( int px ) { editor->setEraserSize( px ); } void MergeWidget::eraserToggle( bool on ) { if ( !on ) return; editor->setMode( MergeEditor::Erase ); slider->setEnabled( false ); } void MergeWidget::paintToggle( bool on ) { if ( !on ) return; editor->setMode( MergeEditor::Paint ); slider->setEnabled( true ); } void MergeWidget::sprayToggle( bool on ) { if ( !on ) return; editor->setMode( MergeEditor::Spray ); slider->setEnabled( true ); } bool MergeWidget::save() { if ( result.isNull() ) { result = QFileDialog::getSaveFileName ( this, "Save Result As", QString(), "*."+resultFormat ); } if ( result.isNull() ) return false; if ( !merge.save( result, resultFormat.toAscii() ) ) { QMessageBox::critical( this, "CALAMARI error", "Unable to save " + result ); return false; } emit enableSave( false ); return true; } void MergeWidget::saveAs() { QString as = QFileDialog::getSaveFileName ( this, "Save Result As", QString(), "*."+resultFormat ); if ( as.isNull() ) return; if ( !merge.save( as, resultFormat.toAscii() ) ) { QMessageBox::critical( this, "CALAMARI error", "Unable to save " + as ); } } void MergeWidget::setResult( char* resultFile ) { result = resultFile; } void MergeWidget::exportStencils() { freshenConflicts(); QString prefix = result; if ( prefix.isNull() ) { prefix = QFileDialog::getSaveFileName ( this, "Select Filename Prefix for Stencils", QString(), "*.*", 0, QFileDialog::DontConfirmOverwrite ); } if ( prefix.isNull() ) return; if ( prefix.contains( '.' ) ) prefix.truncate( prefix.lastIndexOf( '.' ) ); base_theirs.save( prefix + "_stencil_theirs.png", "PNG" ); base_yours.save( prefix + "_stencil_yours.png", "PNG" ); conflicts.save( prefix + "_stencil_conflicts.png", "PNG" ); QWhatsThis::showText( mapToGlobal(QPoint(0,0)), "Saved\n" + prefix + "_stencil_theirs.png\n" + prefix + "_stencil_yours.png\n" + prefix + "_stencil_conflicts.png\n", this ); } void MergeWidget::freshenConflicts() { //Do diffs vs. base. if ( base_theirs_t != tolerance ) imageDiff( base, leg1, &base_theirs, tolerance ); if ( base_yours_t != tolerance ) imageDiff( base, leg2, &base_yours, tolerance ); base_theirs_t = base_yours_t = tolerance; //Conflicts. if ( conflicts_t != tolerance ) { //Diffs between the legs. QBitmap theirs_yours( base.size() ); imageDiff( leg1, leg2, &theirs_yours, tolerance ); //The conflict stencil is the result of drawing //all three other stencils on top of each other. conflicts.clear(); QPainter p( &conflicts ); p.setPen( Qt::color1 ); p.drawPixmap( 0, 0, base_theirs ); p.drawPixmap( 0, 0, base_yours ); p.drawPixmap( 0, 0, theirs_yours ); } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#8 | 5549 | Sam Stafford |
Fix another edge case bug where Qt's behavior is the opposite of what I'd expect - when an empty clip region is set, the clip region is cleared entirely, as if a FULL clip region had been set. The resulting bug was that any image which had zero conflicts would show up as one gigantic conflict - ack! The code now checks for this case and bails out of any painting operation that's about to use an empty clip region. |
||
#7 | 5539 | Sam Stafford | Kick off another window to merge alpha channels, if present. | ||
#6 | 5534 | Sam Stafford |
A brand new help file, a bit of cosmetic sprucing, one critical bug fix, and a partridge in a pear tree. |
||
#5 | 5527 | Sam Stafford |
Diff options in merge mode, and an "export stencils" command for people who like that sort of thing. Also, a fresh build. |
||
#4 | 5524 | Sam Stafford | Eraser and spraypaint tools, and "Save" command. | ||
#3 | 5519 | Sam Stafford |
Added the paintbrush tool. Now we're getting somewhere. |
||
#2 | 5516 | Sam Stafford | The M is for Merge. | ||
#1 | 5511 | Sam Stafford | Continued infrastructure work. |