blob: fd39e07450b771f57ab445ee937f8971c54ddc50 [file] [log] [blame]
// Copyright 2010-2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "gui/character_pad/hand_writing_canvas.h"
#include <QtGui/QtGui>
#include "gui/character_pad/hand_writing.h"
namespace mozc {
namespace gui {
HandWritingCanvas::HandWritingCanvas(QWidget *parent)
: QWidget(parent),
list_widget_(NULL), is_drawing_(false),
handwriting_status_(handwriting::HANDWRITING_NO_ERROR) {
setBackgroundRole(QPalette::Base);
setAutoFillBackground(true);
strokes_.reserve(128);
QObject::connect(this, SIGNAL(startRecognition()),
&recognizer_thread_, SLOT(startRecognition()),
Qt::QueuedConnection);
QObject::connect(&recognizer_thread_, SIGNAL(candidatesUpdated()),
this, SLOT(listUpdated()), Qt::QueuedConnection);
qRegisterMetaType<mozc::handwriting::HandwritingStatus>(
"mozc::handwriting::HandwritingStatus");
QObject::connect(&recognizer_thread_,
SIGNAL(statusUpdated(mozc::handwriting::HandwritingStatus)),
this,
SLOT(statusUpdated(mozc::handwriting::HandwritingStatus)),
Qt::QueuedConnection);
recognizer_thread_.Start();
}
HandWritingCanvas::~HandWritingCanvas() {
recognizer_thread_.quit();
recognizer_thread_.wait();
}
void HandWritingCanvas::setListWidget(QListWidget *list_widget) {
list_widget_ = list_widget;
QObject::connect(list_widget_, SIGNAL(itemSelected(const QListWidgetItem*)),
&recognizer_thread_,
SLOT(itemSelected(const QListWidgetItem*)),
Qt::QueuedConnection);
}
void HandWritingCanvas::clear() {
handwriting_status_ = handwriting::HANDWRITING_NO_ERROR;
strokes_.clear();
update();
is_drawing_ = false;
}
void HandWritingCanvas::revert() {
handwriting_status_ = handwriting::HANDWRITING_NO_ERROR;
if (!strokes_.empty()) {
strokes_.resize(strokes_.size() - 1);
update();
recognize();
}
is_drawing_ = false;
}
void HandWritingCanvas::restartRecognition() {
// We need to call |recognize()| instead of |emit startRecognition()| here
// so that the current stroke has a new timestamp.
recognize();
}
void HandWritingCanvas::paintEvent(QPaintEvent *) {
QPainter painter(this);
// show grid information
painter.setPen(QPen(Qt::gray, 1));
const QRect border_rect(0, 0, width() - 1, height() - 1);
painter.drawRect(border_rect);
const int diff = static_cast<int>(height() * 0.05);
const int margin = static_cast<int>(height() * 0.04);
painter.drawLine(width() / 2 - diff, height() / 2,
width() / 2 + diff, height() / 2);
painter.drawLine(width() / 2, height() / 2 - diff,
width() / 2, height() / 2 + diff);
painter.drawLine(margin, margin, margin + diff, margin);
painter.drawLine(margin, margin, margin, margin + diff);
painter.drawLine(width() - margin - diff, margin,
width() - margin, margin);
painter.drawLine(width() - margin, margin,
width() - margin, margin + diff);
painter.drawLine(margin, height() - margin - diff,
margin, height() - margin);
painter.drawLine(margin, height() - margin,
margin + diff, height() - margin);
painter.drawLine(width() - margin - diff, height() - margin,
width() - margin, height() - margin);
painter.drawLine(width() - margin, height() - margin - diff,
width() - margin, height() - margin);
if (strokes_.empty()) {
painter.drawText(margin + 10, margin + 10,
width() - margin - 20, height() / 2,
Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap,
QObject::tr("Draw a character here"));
}
// show pen strokes
painter.setPen(QPen(Qt::black, 3));
for (int i = 0; i < strokes_.size(); ++i) {
for (int j = 1; j < strokes_[i].size(); ++j) {
const int x1 = static_cast<int>(strokes_[i][j - 1].first * width());
const int y1 = static_cast<int>(strokes_[i][j - 1].second * height());
const int x2 = static_cast<int>(strokes_[i][j].first * width());
const int y2 = static_cast<int>(strokes_[i][j].second * height());
painter.drawLine(x1, y1, x2, y2);
}
}
if (handwriting_status_ != handwriting::HANDWRITING_NO_ERROR) {
painter.setPen(QPen(Qt::red, 2));
QString warning_message;
switch (handwriting_status_) {
case handwriting::HANDWRITING_ERROR:
warning_message = QObject::tr("error");
break;
case handwriting::HANDWRITING_NETWORK_ERROR:
warning_message = QObject::tr("network error");
break;
case handwriting::HANDWRITING_UNKNOWN_ERROR:
default:
warning_message = QObject::tr("unknown error");
break;
}
painter.drawText(0, 0, width() - margin, height() - margin,
Qt::AlignRight | Qt::AlignBottom | Qt::TextWordWrap,
warning_message);
}
emit canvasUpdated();
}
void HandWritingCanvas::recognize() {
if (strokes_.empty()) {
return;
}
recognizer_thread_.SetStrokes(strokes_);
emit startRecognition();
}
void HandWritingCanvas::listUpdated() {
vector<string> candidates;
recognizer_thread_.GetCandidates(&candidates);
list_widget_->clear();
for (size_t i = 0; i < candidates.size(); ++i) {
list_widget_->addItem(QString::fromUtf8(candidates[i].c_str()));
}
}
void HandWritingCanvas::statusUpdated(handwriting::HandwritingStatus status) {
handwriting_status_ = status;
update();
}
void HandWritingCanvas::mousePressEvent(QMouseEvent *event) {
if (event->button() != Qt::LeftButton) {
return;
}
strokes_.resize(strokes_.size() + 1);
const float x = static_cast<float>(event->pos().x()) / width();
const float y = static_cast<float>(event->pos().y()) / height();
strokes_.back().push_back(make_pair(x, y));
is_drawing_ = true;
update();
}
void HandWritingCanvas::mouseMoveEvent(QMouseEvent *event) {
if (!is_drawing_) {
return;
}
const float x = static_cast<float>(event->pos().x()) / width();
const float y = static_cast<float>(event->pos().y()) / height();
strokes_.back().push_back(make_pair(x, y));
update();
}
void HandWritingCanvas::mouseReleaseEvent(QMouseEvent *event) {
if (event->button() != Qt::LeftButton) {
return;
}
is_drawing_ = false;
update();
recognize();
}
size_t HandWritingCanvas::strokes_size() const {
return strokes_.size();
}
} // namespace gui
} // namespace mozc