#include "CalamariWindow.h" #include "DiffWidget.h" #include "MergeWidget.h" #include "ColorOptsDialog.h" #include <QAction> #include <QApplication> #include <QButtonGroup> #include <QCheckBox> #include <QComboBox> #include <QLabel> #include <QLayout> #include <QMenu> #include <QMenuBar> #include <QMessageBox> #include <QPainter> #include <QSettings> #include <QStatusBar> #include <QToolBar> #include <QToolButton> #include <math.h> CalamariWindow::CalamariWindow(char* file1, char* file2) : QMainWindow(0, 0) { save = 0x0; base = theirs = yours = 0x0; baseWidget = diffWidget = new DiffWidget( file1, file2 ); loadOpts(); initDiffToolbar(); setCentralWidget( baseWidget ); zoomFactor = 0; baseWidget->setScale( 0 ); connect( baseWidget, SIGNAL( showMessage( QString, int ) ), statusBar(), SLOT( showMessage( QString, int ) ) ); } CalamariWindow::CalamariWindow(char* file1, char* file2, char* file3, char* file4) : QMainWindow(0,0) { save = 0x0; base = file1; theirs = file2; yours = file3; baseWidget = mergeWidget = new MergeWidget( file1, file2, file3 ); loadOpts(); initMergeToolbar(); setCentralWidget( baseWidget ); mergeWidget->autoMerge(); mergeWidget->setBrushSize( brushSize ); mergeWidget->setResult( file4 ); zoomFactor = 0; baseWidget->setScale( 0 ); connect( baseWidget, SIGNAL( showMessage( QString, int ) ), statusBar(), SLOT( showMessage( QString, int ) ) ); } CalamariWindow::~CalamariWindow() { } void CalamariWindow::closeEvent( QCloseEvent* e ) { saveOpts(); if ( save && save->isEnabled() ) { switch( QMessageBox::question( this, "Mrh?", "Save merge result before closing?", QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel ) ) { case QMessageBox::Yes: if ( !mergeWidget->save() ) { e->setAccepted( false ); return; } break; case QMessageBox::No: break; case QMessageBox::Cancel: e->setAccepted( false ); return; } } QMainWindow::closeEvent( e ); } void CalamariWindow::loadOpts() { QSettings s( QSettings::UserScope, "Perforce", "CALAMARI" ); QColor m; m.setRgba( s.value( "stencil", palette().dark().color().rgba() ).toUInt() ); QColor c; c.setRgba( s.value( "conflict", QColor("red").rgba() ).toUInt() ); baseWidget->setMaskColor( m ); baseWidget->setConflictColor( c ); baseWidget->setTolerance( s.value( "tolerance", 0 ).toInt() ); brushSize = s.value( "brushSize", 16 ).toInt(); eraserSize = s.value( "eraserSize", 16 ).toInt(); } void CalamariWindow::colorOpts() { ColorOptsDialog* d = new ColorOptsDialog ( baseWidget->getMaskColor(), baseWidget->getConflictColor(), baseWidget->getTolerance() ); connect( d, SIGNAL( setMaskColor(QColor) ), baseWidget, SLOT( setMaskColor(QColor) ) ); connect( d, SIGNAL( setConflictColor(QColor) ), baseWidget, SLOT( setConflictColor(QColor) ) ); connect( d, SIGNAL( setTolerance(int) ), baseWidget, SLOT( setTolerance(int) ) ); d->exec(); saveOpts(); } void CalamariWindow::saveOpts() { QSettings s( QSettings::UserScope, "Perforce", "CALAMARI" ); s.setValue( "stencil", baseWidget->getMaskColor().rgba() ); s.setValue( "conflict", baseWidget->getConflictColor().rgba() ); s.setValue( "tolerance", baseWidget->getTolerance() ); s.setValue( "brushSize", brushSize ); s.setValue( "eraserSize", eraserSize ); } void CalamariWindow::setAutoSize( bool a ) { if ( a ) { baseWidget->setScale( 0 ); } else { baseWidget->setScale( pow( 2.0, zoomFactor ) ); } } void CalamariWindow::setZoom( int index ) { zoomFactor = zoomList->itemData( index ).toInt(); double scale = pow( 2.0, zoomFactor ); baseWidget->setScale( scale ); } void CalamariWindow::addMaskOpts( QToolBar* tbar ) { QAction* colOpts = new QAction( QIcon( ":/icons/color.png" ), "Set color options", 0x0 ); tbar->addAction( colOpts ); connect( colOpts, SIGNAL( triggered() ), this, SLOT( colorOpts() ) ); colOpts->setEnabled( true ); } void CalamariWindow::maskToggled( bool toggled ) { //If one mask button just got toggled on, toggle off the rest. if ( toggled ) { for ( QList<QAction*>::iterator i = maskActions.begin() ; i != maskActions.end() ; i++ ) { if ( (*i) != sender() ) (*i)->setChecked( false ); } } } void CalamariWindow::setBrushSize( bool on ) { if ( !on ) return; //A hack - the paintbrush size is stored in the objectName //of the sender, which is one of many QActions in a menu. brushSize = sender()->objectName().toInt(); mergeWidget->setBrushSize( brushSize ); } void CalamariWindow::setEraserSize( bool on ) { if ( !on ) return; //Same as brush size. eraserSize = sender()->objectName().toInt(); mergeWidget->setEraserSize( eraserSize ); } void CalamariWindow::addZoomOpts( QToolBar* tbar ) { QLabel* zLabel = new QLabel( "Zoom:" ); tbar->addWidget( zLabel ); zoomList = new QComboBox; tbar->addWidget( zoomList ); int d; int off = 3; zoomList->setInsertPolicy( QComboBox::InsertAtBottom ); for ( int z = -3 ; z <= 3 ; z++ ) { if ( z < 0 ) { d = pow( 2, -z ); zoomList->insertItem( z + off, "1/" + QString::number( d ) + " x", z ); } else { d = pow( 2, z ); zoomList->insertItem( z + off, QString::number( d ) + " x", z ); } } zoomList->setCurrentIndex( 0 + off ); connect( zoomList, SIGNAL(activated(int)), this, SLOT(setZoom(int)) ); QCheckBox* asize = new QCheckBox( "Fit to window" ); tbar->addWidget( asize ); connect( asize, SIGNAL( toggled(bool) ), this, SLOT( setAutoSize(bool) ) ); connect( asize, SIGNAL( toggled(bool) ), zoomList, SLOT( setDisabled(bool) ) ); asize->setChecked( true ); } void CalamariWindow::initDiffToolbar() { QToolBar* tbar = addToolBar( "CALAMARI" ); //All stencil buttons should follow this template. Note the special hookups //that enable the one-or-none toggle behavior. QAction* diffMask = new QAction( QIcon( ":/icons/diff.png" ), "Diff stencil", 0x0 ); diffMask->setCheckable( true ); tbar->addAction( diffMask ); maskActions.append( diffMask ); connect( diffMask, SIGNAL( toggled(bool) ), this, SLOT(maskToggled(bool) ) ); connect( diffMask, SIGNAL( toggled(bool) ), diffWidget, SLOT( setDiffMask(bool) ) ); addMaskOpts( tbar ); tbar->addSeparator(); addZoomOpts( tbar ); tbar->setMovable( false ); tbar->toggleViewAction()->setEnabled( false ); setMinimumWidth( tbar->sizeHint().width() ); } void CalamariWindow::initMergeToolbar() { QToolBar* tbar = addToolBar( "CALAMARI" ); //All stencil buttons should follow this template. Note the special hookups //that enable the one-or-none toggle behavior. QAction* theirMask = new QAction( QIcon( ":/icons/theirs.png" ), "Theirs stencil", 0x0 ); theirMask->setCheckable( true ); tbar->addAction( theirMask ); maskActions.append( theirMask ); connect( theirMask, SIGNAL( toggled(bool) ), this, SLOT( maskToggled(bool) ) ); connect( theirMask, SIGNAL( toggled(bool) ), mergeWidget, SLOT( setTheirsMask(bool) ) ); QAction* yourMask = new QAction( QIcon( ":/icons/yours.png" ), "Yours stencil", 0x0 ); yourMask->setCheckable( true ); tbar->addAction( yourMask ); maskActions.append( yourMask ); connect( yourMask, SIGNAL( toggled(bool) ), this, SLOT( maskToggled(bool) ) ); connect( yourMask, SIGNAL( toggled(bool) ), mergeWidget, SLOT( setYoursMask(bool) ) ); QAction* conflictMask = new QAction( QIcon( ":/icons/conflict.png" ), "Conflict stencil", 0x0 ); conflictMask->setCheckable( true ); tbar->addAction( conflictMask ); maskActions.append( conflictMask ); connect( conflictMask, SIGNAL( toggled(bool) ), this, SLOT( maskToggled(bool) ) ); connect( conflictMask, SIGNAL( toggled(bool) ), mergeWidget, SLOT( setConflictMask(bool) ) ); addMaskOpts( tbar ); tbar->addSeparator(); addZoomOpts( tbar ); QWidget* s = new QWidget; s->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) ); tbar->addWidget( s ); tbar->setMovable( false ); tbar->toggleViewAction()->setEnabled( false ); setMinimumWidth( tbar->sizeHint().width() ); addToolBarBreak(); tbar = addToolBar( "Merge tools" ); tbar->setMovable( false ); QAction* autoMerge = new QAction( QIcon( ":/icons/auto.png" ), "Auto Merge", 0x0 ); tbar->addAction( autoMerge ); connect( autoMerge, SIGNAL( triggered() ), mergeWidget, SLOT( autoMerge() ) ); tbar->addSeparator(); QButtonGroup* tools = new QButtonGroup( this ); QToolButton* paintBrush = new QToolButton; tools->addButton( paintBrush ); paintBrush->setIcon( QIcon( ":/icons/paint.png" ) ); paintBrush->setToolTip( "Paint" ); paintBrush->setCheckable( true ); paintBrush->setPopupMode( QToolButton::MenuButtonPopup ); tbar->addWidget( paintBrush ); connect( paintBrush, SIGNAL( toggled(bool) ), mergeWidget, SLOT( paintToggle(bool) ) ); paintBrush->setMenu( new QMenu( "Brush size", paintBrush ) ); QString px; QAction* a; QPixmap i( QSize( 18, 18 ) ); QPainter pt; QActionGroup* bs = new QActionGroup( this ); for ( int p = 0 ; p < 7 ; p++ ) { i.fill( QColor( 0, 0, 0, 0 ) ); pt.begin( &i ); pt.setBrush( QColor( 0, 0, 0 ) ); pt.setRenderHint( QPainter::Antialiasing ); pt.drawPoint( 9, 9 ); pt.drawEllipse( 9 - p, 9 - p, p * 2, p * 2 ); pt.end(); px = QString::number( pow( 2, p ) ); a = paintBrush->menu()->addAction( QIcon( i ), px + QString( " pt" ) ); a->setCheckable( true ); bs->addAction( a ); a->setObjectName( px ); connect( a, SIGNAL( toggled(bool) ), this, SLOT( setBrushSize(bool) ) ); if ( pow( 2, p ) == brushSize ) a->setChecked( true ); } QToolButton* spray = new QToolButton; tools->addButton( spray ); spray->setIcon( QIcon( ":/icons/spray.png" ) ); spray->setToolTip( "Spray" ); spray->setCheckable( true ); tbar->addWidget( spray ); connect( spray, SIGNAL( toggled(bool) ), mergeWidget, SLOT( sprayToggle(bool) ) ); QToolButton* eraser = new QToolButton; tools->addButton( eraser ); eraser->setIcon( QIcon( ":/icons/eraser.png" ) ); eraser->setToolTip( "Erase" ); eraser->setCheckable( true ); eraser->setPopupMode( QToolButton::MenuButtonPopup ); tbar->addWidget( eraser ); connect( eraser, SIGNAL( toggled(bool) ), mergeWidget, SLOT( eraserToggle(bool) ) ); eraser->setMenu( new QMenu( "Eraser size", eraser ) ); QActionGroup* es = new QActionGroup( this ); for ( int p = 0 ; p < 7 ; p++ ) { i.fill( QColor( 0, 0, 0, 0 ) ); pt.begin( &i ); pt.setPen( QColor( 0, 0, 0 ) ); pt.setBrush( QColor( 255, 255, 255 ) ); pt.drawRect( 9 - p, 9 - p, p * 2, p * 2 ); pt.end(); px = QString::number( pow( 2, p ) ); a = eraser->menu()->addAction( QIcon( i ), px + QString( " pt" ) ); a->setCheckable( true ); es->addAction( a ); a->setObjectName( px ); connect( a, SIGNAL( toggled(bool) ), this, SLOT( setEraserSize(bool) ) ); if ( pow( 2, p ) == eraserSize ) a->setChecked( true ); } tbar->addSeparator(); save = new QAction( QIcon( ":/icons/save.png" ), "&Save", this ); save->setShortcut( QKeySequence( "Ctrl+S" ) ); tbar->addAction( save ); connect( save, SIGNAL( triggered() ), mergeWidget, SLOT( save() ) ); connect( mergeWidget, SIGNAL( enableSave(bool) ), save, SLOT( setEnabled(bool) ) ); QMenu* file = menuBar()->addMenu( "&File" ); file->addAction( save ); file->addAction( "Save &As...", mergeWidget, SLOT( saveAs() ) ); file->addSeparator(); file->addAction( "E&xit", qApp, SLOT( closeAllWindows() ) ); }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#14 | 6281 | Sam Stafford | CALAMARI now builds with VS2005 and Qt 4.3.3. | ||
#13 | 5539 | Sam Stafford | Kick off another window to merge alpha channels, if present. | ||
#12 | 5534 | Sam Stafford |
A brand new help file, a bit of cosmetic sprucing, one critical bug fix, and a partridge in a pear tree. |
||
#11 | 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. |
||
#10 | 5524 | Sam Stafford | Eraser and spraypaint tools, and "Save" command. | ||
#9 | 5520 | Sam Stafford |
Configurable brush sizes, complete with procedurally generated icons. Spiffy. |
||
#8 | 5519 | Sam Stafford |
Added the paintbrush tool. Now we're getting somewhere. |
||
#7 | 5516 | Sam Stafford | The M is for Merge. | ||
#6 | 5515 | Sam Stafford |
A little more groundwork for merging. Color options are now saved automatically, and may include alpha channels (semitransparent stencils are nifty). |
||
#5 | 5512 | Sam Stafford | UI reshuffling - pushed stencil-related options into a dialog. | ||
#4 | 5511 | Sam Stafford | Continued infrastructure work. | ||
#3 | 5505 | Sam Stafford | Add "diff stencil". | ||
#2 | 5502 | Sam Stafford |
Status bar with handy information, and infrastructure to allow ImageProjectors to have frames. |
||
#1 | 5501 | Sam Stafford |
Codename CALAMARI. Built with Qt 4.1.3 - needs QtCore4.dll and QtGui4.dll to run. |