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
}