| 1 |
/*************************************************************************** |
| 2 |
* Copyright (c) 2009 Enrico Ros * |
| 3 |
* 2009 Enrico Ros <enrico.ros@email.it> * |
| 4 |
* 2009 Alberto Scarpa <skaal.sl@gmail.com> * |
| 5 |
* * |
| 6 |
* Permission is hereby granted, free of charge, to any person * |
| 7 |
* obtaining a copy of this software and associated documentation * |
| 8 |
* files (the "Software"), to deal in the Software without * |
| 9 |
* restriction, including without limitation the rights to use, * |
| 10 |
* copy, modify, merge, publish, distribute, sublicense, and/or sell * |
| 11 |
* copies of the Software, and to permit persons to whom the * |
| 12 |
* Software is furnished to do so, subject to the following * |
| 13 |
* conditions: * |
| 14 |
* * |
| 15 |
* The above copyright notice and this permission notice shall be * |
| 16 |
* included in all copies or substantial portions of the Software. * |
| 17 |
* * |
| 18 |
***************************************************************************/ |
| 19 |
|
| 20 |
#include "AppWidget.h" |
| 21 |
#include "AbstractGame.h" |
| 22 |
#include "InputUtils.h" |
| 23 |
#include "ScreenCapture.h" |
| 24 |
#include "WCGame.h" |
| 25 |
#include "ocr/Ocr.h" |
| 26 |
#include "ui_AppWidget.h" |
| 27 |
#include <QApplication> |
| 28 |
#include <QDesktopWidget> |
| 29 |
#include <QPaintEvent> |
| 30 |
#include <QPainter> |
| 31 |
#include <QPixmap> |
| 32 |
#include <QPoint> |
| 33 |
#include <QSettings> |
| 34 |
#include <QDirIterator> |
| 35 |
#include <QTimer> |
| 36 |
#include <QDebug> |
| 37 |
|
| 38 |
#define DEFAULT_WIDTH 320 |
| 39 |
#define DEFAULT_HEIGHT 41 |
| 40 |
|
| 41 |
|
| 42 |
class RegionWidget : public QWidget { |
| 43 |
public: |
| 44 |
RegionWidget() : QWidget(0, Qt::CustomizeWindowHint | Qt::FramelessWindowHint) |
| 45 |
{ |
| 46 |
setAttribute(Qt::WA_TranslucentBackground); |
| 47 |
setAttribute(Qt::WA_OpaquePaintEvent); |
| 48 |
hide(); |
| 49 |
} |
| 50 |
int rX, rY, rWidth, rHeight; |
| 51 |
void setStartPos( const QPoint & pos ) |
| 52 |
{ |
| 53 |
startPos = pos; |
| 54 |
} |
| 55 |
void setEndPos( const QPoint & pos ) |
| 56 |
{ |
| 57 |
endPos = pos; |
| 58 |
rX = qMin( startPos.x(), endPos.x() ); |
| 59 |
rY = qMin( startPos.y(), endPos.y() ); |
| 60 |
rWidth = qMax( startPos.x(), endPos.x() ) - rX + 1; |
| 61 |
rHeight = qMax( startPos.y(), endPos.y() ) - rY + 1; |
| 62 |
setShown( rWidth > 0 && rHeight > 0 ); |
| 63 |
setGeometry( rX, rY, rWidth, rHeight ); |
| 64 |
} |
| 65 |
protected: |
| 66 |
void paintEvent(QPaintEvent * event) |
| 67 |
{ |
| 68 |
QPainter p(this); |
| 69 |
p.setCompositionMode(QPainter::CompositionMode_Source); |
| 70 |
p.fillRect(event->rect(), QColor(255, 0, 0, 64)); |
| 71 |
p.drawRect(0, 0, width() - 1, height() - 1); |
| 72 |
} |
| 73 |
private: |
| 74 |
QPoint startPos, endPos; |
| 75 |
}; |
| 76 |
|
| 77 |
|
| 78 |
AppWidget::AppWidget(QWidget *parent) |
| 79 |
: QWidget(parent) |
| 80 |
, ui(new Ui::AppWidgetClass) |
| 81 |
#if defined(Q_OS_WIN) |
| 82 |
, m_settings( new QSettings( "autogram.ini", QSettings::IniFormat ) ) |
| 83 |
#else |
| 84 |
, m_settings( new QSettings() ) |
| 85 |
#endif |
| 86 |
, m_game( 0 ) |
| 87 |
, m_capture( 0 ) |
| 88 |
, m_ocr( 0 ) |
| 89 |
, m_pickingRegion( 0 ) |
| 90 |
{ |
| 91 |
// create ui |
| 92 |
ui->setupUi( this ); |
| 93 |
QDesktopWidget dw; |
| 94 |
ui->left->setMaximum( dw.width() ); |
| 95 |
ui->top->setMaximum( dw.height() ); |
| 96 |
ui->width->setMaximum( dw.width() ); |
| 97 |
ui->height->setMaximum( dw.height() ); |
| 98 |
// init defaults.. |
| 99 |
if ( !m_settings->contains( "rect/left" ) ) { |
| 100 |
ui->left->setValue( (dw.width() - DEFAULT_WIDTH) / 3 ); |
| 101 |
ui->top->setValue( (dw.height() - DEFAULT_HEIGHT) / 3 ); |
| 102 |
ui->width->setValue( DEFAULT_WIDTH ); |
| 103 |
ui->height->setValue( DEFAULT_HEIGHT ); |
| 104 |
} |
| 105 |
// ..or reload previous values |
| 106 |
else { |
| 107 |
ui->left->setValue( m_settings->value( "rect/left" ).toInt() ); |
| 108 |
ui->top->setValue( m_settings->value( "rect/top" ).toInt() ); |
| 109 |
ui->width->setValue( m_settings->value( "rect/width" ).toInt() ); |
| 110 |
ui->height->setValue( m_settings->value( "rect/height" ).toInt() ); |
| 111 |
ui->frequency->setValue( m_settings->value( "rect/frequency" ).toInt() ); |
| 112 |
ui->onTop->setChecked( m_settings->value( "rect/ontop" ).toBool() ); |
| 113 |
} |
| 114 |
connect( ui->left, SIGNAL(valueChanged(int)), this, SLOT(slotCapParamsChanged()) ); |
| 115 |
connect( ui->top, SIGNAL(valueChanged(int)), this, SLOT(slotCapParamsChanged()) ); |
| 116 |
connect( ui->width, SIGNAL(valueChanged(int)), this, SLOT(slotCapParamsChanged()) ); |
| 117 |
connect( ui->height, SIGNAL(valueChanged(int)), this, SLOT(slotCapParamsChanged()) ); |
| 118 |
connect( ui->frequency, SIGNAL(valueChanged(int)), this, SLOT(slotCapParamsChanged()) ); |
| 119 |
connect( ui->onTop, SIGNAL(toggled(bool)), this, SLOT(slotOnTopChanged()) ); |
| 120 |
slotOnTopChanged(); |
| 121 |
|
| 122 |
// create the capture |
| 123 |
m_capture = new ScreenCapture( this ); |
| 124 |
connect( m_capture, SIGNAL(gotPixmap(const QPixmap &, const QPoint &)), |
| 125 |
this, SLOT(slotProcessPixmap(const QPixmap &, const QPoint &)) ); |
| 126 |
slotCapParamsChanged(); |
| 127 |
|
| 128 |
// create the OCR, train with font and saved glyphs |
| 129 |
m_ocr = new Ocr(); |
| 130 |
#if 0 |
| 131 |
QFont font( "Arial", 32 ); |
| 132 |
font.setBold( true ); |
| 133 |
m_ocr->trainFont( font ); |
| 134 |
#endif |
| 135 |
QString dirString = QDir::toNativeSeparators(QCoreApplication::applicationDirPath()) + QDir::separator() + "wc-glyphs"; |
| 136 |
QDirIterator dIt( dirString, QStringList() << "glyph_*.png", QDir::Files ); |
| 137 |
if ( !dIt.hasNext() ) |
| 138 |
qWarning() << "ERROR: can't load glyphs.. something br0ken?" << dirString; |
| 139 |
while ( dIt.hasNext() ) { |
| 140 |
QString fileName = dIt.next(); |
| 141 |
QChar character = fileName.right( 5 ).at( 0 ); |
| 142 |
QImage image( fileName, "PNG" ); |
| 143 |
if ( !image.isNull() ) { |
| 144 |
m_ocr->trainGlyph( image, character ); |
| 145 |
qWarning() << "loaded" << fileName << character; |
| 146 |
} else |
| 147 |
qWarning() << "ERROR loading" << fileName << character; |
| 148 |
} |
| 149 |
|
| 150 |
// ### TEMP |
| 151 |
m_capture->setEnabled( true ); |
| 152 |
} |
| 153 |
|
| 154 |
AppWidget::~AppWidget() |
| 155 |
{ |
| 156 |
saveSettings(); |
| 157 |
delete m_pickingRegion; |
| 158 |
delete m_settings; |
| 159 |
delete m_ocr; |
| 160 |
delete m_game; |
| 161 |
delete m_capture; |
| 162 |
delete ui; |
| 163 |
} |
| 164 |
|
| 165 |
void AppWidget::mousePressEvent( QMouseEvent * event ) |
| 166 |
{ |
| 167 |
if ( m_pickingRegion ) |
| 168 |
m_pickingRegion->setStartPos( event->globalPos() ); |
| 169 |
} |
| 170 |
|
| 171 |
void AppWidget::mouseMoveEvent( QMouseEvent * event ) |
| 172 |
{ |
| 173 |
if ( m_pickingRegion ) |
| 174 |
m_pickingRegion->setEndPos( event->globalPos() ); |
| 175 |
} |
| 176 |
|
| 177 |
void AppWidget::mouseReleaseEvent( QMouseEvent * event ) |
| 178 |
{ |
| 179 |
if ( m_pickingRegion ) { |
| 180 |
m_pickingRegion->setEndPos( event->globalPos() ); |
| 181 |
ui->left->setValue( m_pickingRegion->rX ); |
| 182 |
ui->top->setValue( m_pickingRegion->rY ); |
| 183 |
///ui->width->setValue( m_pickingRegion->rWidth ); |
| 184 |
///ui->height->setValue( m_pickingRegion->rHeight ); |
| 185 |
slotCapParamsChanged(); |
| 186 |
delete m_pickingRegion; |
| 187 |
m_pickingRegion = 0; |
| 188 |
releaseMouse(); |
| 189 |
} |
| 190 |
} |
| 191 |
|
| 192 |
void AppWidget::saveSettings() |
| 193 |
{ |
| 194 |
m_settings->setValue( "rect/left", ui->left->value() ); |
| 195 |
m_settings->setValue( "rect/top", ui->top->value() ); |
| 196 |
m_settings->setValue( "rect/width", ui->width->value() ); |
| 197 |
m_settings->setValue( "rect/height", ui->height->value() ); |
| 198 |
m_settings->setValue( "rect/frequency", ui->frequency->value() ); |
| 199 |
m_settings->setValue( "rect/ontop", ui->onTop->isChecked() ); |
| 200 |
} |
| 201 |
|
| 202 |
void AppWidget::on_gameNo_toggled( bool checked ) |
| 203 |
{ |
| 204 |
if ( checked ) { |
| 205 |
delete m_game; |
| 206 |
m_game = 0; |
| 207 |
} |
| 208 |
} |
| 209 |
|
| 210 |
void AppWidget::on_gameWc_toggled( bool checked ) |
| 211 |
{ |
| 212 |
if ( checked ) { |
| 213 |
delete m_game; |
| 214 |
m_game = new WCGame( this ); |
| 215 |
} |
| 216 |
} |
| 217 |
|
| 218 |
void AppWidget::on_gameWcLearn_toggled(bool checked) |
| 219 |
{ |
| 220 |
if ( checked ) { |
| 221 |
//delete m_game; |
| 222 |
//m_game = new WCLearn( this ); |
| 223 |
} |
| 224 |
} |
| 225 |
|
| 226 |
void AppWidget::on_pickRegionButton_clicked() |
| 227 |
{ |
| 228 |
m_pickingRegion = new RegionWidget(); |
| 229 |
grabMouse( Qt::CrossCursor ); |
| 230 |
} |
| 231 |
|
| 232 |
void AppWidget::on_trainButton_clicked() |
| 233 |
{ |
| 234 |
if ( m_game ) |
| 235 |
m_game->train( m_ocr, ui->trainLetters->text(), m_capture->lastPixmap().toImage() ); |
| 236 |
} |
| 237 |
|
| 238 |
void AppWidget::slotOnTopChanged() |
| 239 |
{ |
| 240 |
Qt::WindowFlags flags = windowFlags(); |
| 241 |
if ( ui->onTop->isChecked() ) |
| 242 |
flags |= Qt::WindowStaysOnTopHint; |
| 243 |
else |
| 244 |
flags &= ~Qt::WindowStaysOnTopHint; |
| 245 |
setWindowFlags( flags ); |
| 246 |
show(); |
| 247 |
} |
| 248 |
|
| 249 |
void AppWidget::slotCapParamsChanged() |
| 250 |
{ |
| 251 |
QRect captureRect( ui->left->value(), ui->top->value(), ui->width->value(), ui->height->value() ); |
| 252 |
m_capture->setGeometry( captureRect ); |
| 253 |
m_capture->setFrequency( ui->frequency->value() ); |
| 254 |
ui->capDisplay->setFixedSize( captureRect.size() ); |
| 255 |
} |
| 256 |
|
| 257 |
void AppWidget::slotProcessPixmap( const QPixmap & pixmap, const QPoint & /*cursor*/ ) |
| 258 |
{ |
| 259 |
// highlight pixmap |
| 260 |
if ( m_game ) |
| 261 |
ui->capDisplay->setPixmap( m_game->highlightPixmap( pixmap ) ); |
| 262 |
else |
| 263 |
ui->capDisplay->setPixmap( pixmap ); |
| 264 |
|
| 265 |
// make da move! |
| 266 |
if ( m_game ) |
| 267 |
m_game->run( ui, m_capture, m_ocr ); |
| 268 |
} |