|
|
|
@ -20,7 +20,6 @@
|
|
|
|
|
#include "ccrossfieldwidget.h" |
|
|
|
|
|
|
|
|
|
#include <libqnono/cnonogram.h> |
|
|
|
|
#include <libqnono/cnonogramsolver.h> |
|
|
|
|
|
|
|
|
|
#include <QPainter> |
|
|
|
|
#include <QMouseEvent> |
|
|
|
@ -44,19 +43,13 @@ namespace qcross {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//public
|
|
|
|
|
CCrossFieldWidget::CCrossFieldWidget(CNonogram * picture, QWidget * parent) : QWidget(parent), |
|
|
|
|
m_Picture(picture), |
|
|
|
|
m_OverlayData(NULL), |
|
|
|
|
m_MouseMark(CMT_NONE), |
|
|
|
|
m_ErrorAware(false), |
|
|
|
|
m_NumbersMarkable(true), |
|
|
|
|
m_Time(0), |
|
|
|
|
m_Paused(true), |
|
|
|
|
m_Solved(false), |
|
|
|
|
m_TimerId(-1), |
|
|
|
|
CCrossFieldWidget::CCrossFieldWidget(QWidget * parent) : QWidget(parent), |
|
|
|
|
m_MessageTimeoutId(-1), |
|
|
|
|
m_Clock(NULL), |
|
|
|
|
m_ErrorCount(0), |
|
|
|
|
m_Nonogram(new CNonogram(this)), |
|
|
|
|
m_MouseMark(NonogramMarker::NONE), |
|
|
|
|
m_MouseDown(false), |
|
|
|
|
m_NumbersMarkable(true), |
|
|
|
|
m_Clock(new QLCDNumber(8, this)), |
|
|
|
|
m_LastErrorMark(-1, -1) |
|
|
|
|
{ |
|
|
|
|
// m_Notifier = new QFrame(this);
|
|
|
|
@ -80,51 +73,27 @@ namespace qcross {
|
|
|
|
|
|
|
|
|
|
// m_Notifier->hide();
|
|
|
|
|
|
|
|
|
|
m_Clock = new QLCDNumber(8, this); |
|
|
|
|
m_Clock->setVisible(m_Picture); |
|
|
|
|
|
|
|
|
|
if (m_Picture) { |
|
|
|
|
initialize(); |
|
|
|
|
m_RemainingPixels = m_Picture->solution().blackPixels(); |
|
|
|
|
updateTimeDisplay(); |
|
|
|
|
} |
|
|
|
|
m_Clock->setVisible(false); |
|
|
|
|
|
|
|
|
|
setEnabled(false); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
CCrossFieldWidget::~CCrossFieldWidget() { |
|
|
|
|
cleanup(); |
|
|
|
|
|
|
|
|
|
// delete m_Clock;
|
|
|
|
|
connect(m_Nonogram, SIGNAL(loaded()), SLOT(loaded())); |
|
|
|
|
connect(m_Nonogram, SIGNAL(won(int)), SLOT(won(int))); |
|
|
|
|
connect(m_Nonogram, SIGNAL(timeup()), SLOT(timeup())); |
|
|
|
|
connect(m_Nonogram, SIGNAL(wrongMark(int,int,int)), SLOT(wrongMark(int,int,int))); |
|
|
|
|
connect(m_Nonogram, SIGNAL(changedMark(int,int)), SLOT(changedMark(int,int))); |
|
|
|
|
connect(m_Nonogram, SIGNAL(restarted()), SLOT(restarted())); |
|
|
|
|
connect(m_Nonogram, SIGNAL(paused(int)), SLOT(paused(int))); |
|
|
|
|
connect(m_Nonogram, SIGNAL(resumed(int)), SLOT(resumed(int))); |
|
|
|
|
connect(m_Nonogram, SIGNAL(tick(int)), SLOT(tick(int))); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void CCrossFieldWidget::setPicture(CNonogram * picture) { |
|
|
|
|
if (m_Picture) |
|
|
|
|
cleanup(); |
|
|
|
|
|
|
|
|
|
m_Picture = picture; |
|
|
|
|
|
|
|
|
|
if (m_Picture) { |
|
|
|
|
m_LastErrorMark.setX(-1); |
|
|
|
|
m_LastErrorMark.setY(-1); |
|
|
|
|
m_ErrorCount = 0; |
|
|
|
|
m_Time = picture->timeout(); |
|
|
|
|
m_ErrorAware = picture->timeout(); |
|
|
|
|
m_Solved = false; |
|
|
|
|
|
|
|
|
|
updateTimeDisplay(); |
|
|
|
|
emit timeChanged(m_Time); |
|
|
|
|
|
|
|
|
|
initialize(); |
|
|
|
|
|
|
|
|
|
m_Messages.clear(); |
|
|
|
|
nextMessage(); |
|
|
|
|
|
|
|
|
|
updateMetrics(); |
|
|
|
|
|
|
|
|
|
m_RemainingPixels = m_Picture->solution().blackPixels(); |
|
|
|
|
CCrossFieldWidget::~CCrossFieldWidget() { |
|
|
|
|
qDebug("m_MessageTimeoutId = %i", m_MessageTimeoutId); |
|
|
|
|
if (m_MessageTimeoutId != -1) { |
|
|
|
|
killTimer(m_MessageTimeoutId); |
|
|
|
|
m_MessageTimeoutId = -1; |
|
|
|
|
} |
|
|
|
|
m_Clock->setVisible(m_Picture); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void CCrossFieldWidget::showMessage(const QString message, int timeout, MessageType type) { |
|
|
|
@ -140,134 +109,54 @@ namespace qcross {
|
|
|
|
|
nextMessage(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void CCrossFieldWidget::applyState(QDataStream & stream) { |
|
|
|
|
qDebug("trying to apply state..."); |
|
|
|
|
qDebug("reading basic stuff:"); |
|
|
|
|
|
|
|
|
|
// error state
|
|
|
|
|
stream >> m_ErrorAware; qDebug("m_ErrorAware = %i", int(m_ErrorAware)); |
|
|
|
|
stream >> m_ErrorCount; qDebug("m_ErrorCount = %i", m_ErrorCount); |
|
|
|
|
|
|
|
|
|
// time(out)
|
|
|
|
|
stream >> m_Time; qDebug("m_Time = %i", m_Time); |
|
|
|
|
//public slots
|
|
|
|
|
void CCrossFieldWidget::setNumbersMarkable(bool value) { |
|
|
|
|
m_NumbersMarkable = value; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//protected slots:
|
|
|
|
|
void CCrossFieldWidget::loaded() { |
|
|
|
|
m_LastErrorMark = QPoint(-1, -1); |
|
|
|
|
initialize(); |
|
|
|
|
updateTimeDisplay(); |
|
|
|
|
emit timeChanged(m_Time); |
|
|
|
|
|
|
|
|
|
// paused
|
|
|
|
|
stream >> m_Paused; qDebug("m_Paused = %i", int(m_Paused)); |
|
|
|
|
setDisabled(m_Paused); |
|
|
|
|
|
|
|
|
|
// messages
|
|
|
|
|
int messageCount; |
|
|
|
|
stream >> messageCount; qDebug("messageCount = %i", messageCount); |
|
|
|
|
|
|
|
|
|
m_Messages.clear(); |
|
|
|
|
|
|
|
|
|
unsigned char byteBuffer; |
|
|
|
|
for (int i = 0; i < messageCount; i++) { |
|
|
|
|
qDebug("message #%i:", i); |
|
|
|
|
stream >> byteBuffer; qDebug("type = %i", byteBuffer); |
|
|
|
|
m_Message.type = MessageType(byteBuffer); |
|
|
|
|
if (m_Message.type != Invalid) { |
|
|
|
|
stream >> m_Message.timeout; qDebug("timeout = %i", m_Message.timeout); |
|
|
|
|
stream >> m_Message.text; qDebug("text = %s", qPrintable(m_Message.text)); |
|
|
|
|
|
|
|
|
|
m_Messages.enqueue(m_Message); |
|
|
|
|
if (m_Nonogram->valid()) { |
|
|
|
|
if (m_Nonogram->time() == m_Nonogram->timeout()) { |
|
|
|
|
showMessage(tr("Game started!"), 1000); |
|
|
|
|
} else { |
|
|
|
|
showMessage(tr("Save game loaded!"), 1000); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
nextMessage(); |
|
|
|
|
|
|
|
|
|
// overlaydata
|
|
|
|
|
for (int iy = 0; iy < m_Picture->height(); iy++) { |
|
|
|
|
for (int ix = 0; ix < m_Picture->width(); ix++) { |
|
|
|
|
stream >> byteBuffer; |
|
|
|
|
m_OverlayData[ix][iy] = MarkerType(byteBuffer); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void CCrossFieldWidget::dumpState(QDataStream & stream) { |
|
|
|
|
if (!m_OverlayData || !m_Picture) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
// error state
|
|
|
|
|
stream << m_ErrorAware; |
|
|
|
|
stream << m_ErrorCount; |
|
|
|
|
|
|
|
|
|
// time(out)
|
|
|
|
|
stream << m_Time; |
|
|
|
|
|
|
|
|
|
// paused state
|
|
|
|
|
stream << m_Paused; |
|
|
|
|
|
|
|
|
|
// messages
|
|
|
|
|
// actually we should dump the message queue
|
|
|
|
|
// for now only dump last displayed
|
|
|
|
|
// TODO dump message queue
|
|
|
|
|
stream << 1; // dummy message count
|
|
|
|
|
stream << (unsigned char)(m_Message.type); |
|
|
|
|
if (m_Message.type != Invalid) { |
|
|
|
|
stream << m_Message.timeout; |
|
|
|
|
stream << m_Message.text; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// overlaydata
|
|
|
|
|
for (int iy = 0; iy < m_Picture->height(); iy++) { |
|
|
|
|
for (int ix = 0; ix < m_Picture->width(); ix++) |
|
|
|
|
stream << (unsigned char)(m_OverlayData[ix][iy]); |
|
|
|
|
setEnabled(true); |
|
|
|
|
} else { |
|
|
|
|
nextMessage(); |
|
|
|
|
setEnabled(false); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//public slots
|
|
|
|
|
void CCrossFieldWidget::mark(int x, int y, int type) { |
|
|
|
|
if (type == CMT_NONE || x < 0 || x >= m_Picture->width() || y < 0 || y >= m_Picture->height()) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
MarkerType marker = static_cast<qcross::MarkerType>(type); |
|
|
|
|
|
|
|
|
|
execMark(x, y, marker); |
|
|
|
|
void CCrossFieldWidget::won(int score) { |
|
|
|
|
showMessage(tr("Congratulations! You've solved the puzzle.")); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void CCrossFieldWidget::setTime(int value) { |
|
|
|
|
if (value < 0) |
|
|
|
|
value = 0; |
|
|
|
|
|
|
|
|
|
if (m_Time != value) { |
|
|
|
|
m_Time = value; |
|
|
|
|
|
|
|
|
|
if (m_ErrorAware && !m_Time) { |
|
|
|
|
killTimer(m_TimerId); |
|
|
|
|
m_TimerId = -1; |
|
|
|
|
m_Paused = true; |
|
|
|
|
emit timeUp(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
updateTimeDisplay(); |
|
|
|
|
|
|
|
|
|
emit timeChanged(m_Time); |
|
|
|
|
} |
|
|
|
|
void CCrossFieldWidget::timeup() { |
|
|
|
|
showMessage(tr("Too bad! Time's up."), 0, CCrossFieldWidget::Critical); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void CCrossFieldWidget::setErrorAware(bool value) { |
|
|
|
|
m_ErrorAware = value; |
|
|
|
|
void CCrossFieldWidget::wrongMark(int x, int y, int penaltyTime) { |
|
|
|
|
m_LastErrorMark = QPoint(x, y); |
|
|
|
|
showMessage(tr("Sorry this was not correct: -%1min").arg(penaltyTime/60), 1000, CCrossFieldWidget::Warning); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void CCrossFieldWidget::setNumbersMarkable(bool value) { |
|
|
|
|
m_NumbersMarkable = value; |
|
|
|
|
void CCrossFieldWidget::changedMark(int x, int y) { |
|
|
|
|
update(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void CCrossFieldWidget::start() { |
|
|
|
|
reset(); |
|
|
|
|
resume(); |
|
|
|
|
void CCrossFieldWidget::restarted() { |
|
|
|
|
m_Messages.clear(); |
|
|
|
|
m_LastErrorMark = QPoint(-1, -1); |
|
|
|
|
showMessage(tr("Game restarted."), 1000); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void CCrossFieldWidget::pause() { |
|
|
|
|
if (m_Solved) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
killTimer(m_TimerId); |
|
|
|
|
m_TimerId = -1; |
|
|
|
|
|
|
|
|
|
void CCrossFieldWidget::paused(int time) { |
|
|
|
|
if (m_Message.type != Invalid) { |
|
|
|
|
m_Messages.enqueue(m_Message); |
|
|
|
|
|
|
|
|
@ -276,19 +165,18 @@ namespace qcross {
|
|
|
|
|
m_MessageTimeoutId = -1; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
m_Paused = true; |
|
|
|
|
setEnabled(false); |
|
|
|
|
showMessage(tr("Game paused.")); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void CCrossFieldWidget::resume() { |
|
|
|
|
if (m_Solved) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
m_Paused = false; |
|
|
|
|
void CCrossFieldWidget::resumed(int time) { |
|
|
|
|
setEnabled(true); |
|
|
|
|
showMessage(tr("Game resumed."), 1000); |
|
|
|
|
update(); |
|
|
|
|
m_TimerId = startTimer(1000); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void CCrossFieldWidget::tick(int time) { |
|
|
|
|
updateTimeDisplay(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//protected
|
|
|
|
@ -333,78 +221,34 @@ namespace qcross {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void CCrossFieldWidget::initialize() { |
|
|
|
|
m_OverlayData = new MarkerType *[m_Picture->width()]; |
|
|
|
|
for (int i = 0; i < m_Picture->width(); i++) { |
|
|
|
|
m_OverlayData[i] = new MarkerType[m_Picture->height()]; |
|
|
|
|
for (int j = 0; j < m_Picture->height(); j++) |
|
|
|
|
m_OverlayData[i][j] = CMT_UNMARKED; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int minimumW = max(m_Picture->numbers().maximumNumberCount()+1, 5); |
|
|
|
|
int minimumW = max(m_Nonogram->numbers().maximumNumberCount()+1, 5); |
|
|
|
|
int minimumH = minimumW; |
|
|
|
|
|
|
|
|
|
minimumW += m_Picture->width(); |
|
|
|
|
minimumH += m_Picture->height(); |
|
|
|
|
minimumW += m_Nonogram->width(); |
|
|
|
|
minimumH += m_Nonogram->height(); |
|
|
|
|
|
|
|
|
|
int minimumBoxSize = max(fontMetrics().width(QString::number(m_Picture->height())), fontMetrics().width(QString::number(m_Picture->width()))); |
|
|
|
|
int minimumBoxSize = max(fontMetrics().width(QString::number(m_Nonogram->height())), fontMetrics().width(QString::number(m_Nonogram->width()))); |
|
|
|
|
minimumBoxSize = max(minimumBoxSize, fontInfo().pixelSize() * 1.5); |
|
|
|
|
|
|
|
|
|
minimumW *= minimumBoxSize; |
|
|
|
|
minimumH *= minimumBoxSize; |
|
|
|
|
|
|
|
|
|
setMinimumSize(minimumW, minimumH); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void CCrossFieldWidget::cleanup() { |
|
|
|
|
qDebug("m_TimerId = %i m_MessageTimeoutId = %i", m_TimerId, m_MessageTimeoutId); |
|
|
|
|
if (m_TimerId != -1) { |
|
|
|
|
killTimer(m_TimerId); |
|
|
|
|
m_TimerId = -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (m_MessageTimeoutId != -1) { |
|
|
|
|
killTimer(m_MessageTimeoutId); |
|
|
|
|
m_MessageTimeoutId = -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (m_OverlayData) { |
|
|
|
|
for (int i = 0; i < m_Picture->width(); i++) |
|
|
|
|
delete[] m_OverlayData[i]; |
|
|
|
|
delete[] m_OverlayData; |
|
|
|
|
m_OverlayData = NULL; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void CCrossFieldWidget::reset() { |
|
|
|
|
m_Messages.clear(); |
|
|
|
|
nextMessage(); |
|
|
|
|
|
|
|
|
|
for (int i = 0; i < m_Picture->width(); i++) { |
|
|
|
|
for (int j = 0; j < m_Picture->height(); j++) |
|
|
|
|
m_OverlayData[i][j] = CMT_UNMARKED; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
m_Solved = false; |
|
|
|
|
m_ErrorCount = 0; |
|
|
|
|
m_LastErrorMark.setX(-1); |
|
|
|
|
m_LastErrorMark.setY(-1); |
|
|
|
|
m_RemainingPixels = m_Picture->solution().blackPixels(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool CCrossFieldWidget::checkNoError(int x, int y) { |
|
|
|
|
return (m_OverlayData[x][y] == CMT_MARKED) || m_Picture->solution().pixel(x, y); |
|
|
|
|
updateMetrics(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void CCrossFieldWidget::timerEvent(QTimerEvent * event) { |
|
|
|
|
if (event->timerId() == m_TimerId) |
|
|
|
|
setTime(m_Time + (m_ErrorAware ? -1 : +1)); |
|
|
|
|
else if (event->timerId() == m_MessageTimeoutId) |
|
|
|
|
if (event->timerId() == m_MessageTimeoutId) { |
|
|
|
|
nextMessage(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void CCrossFieldWidget::updateTimeDisplay() { |
|
|
|
|
quint8 seconds = m_Time % 60; |
|
|
|
|
quint8 minutes = m_Time / 60; |
|
|
|
|
m_Clock->setVisible(m_Nonogram->valid()); |
|
|
|
|
|
|
|
|
|
int secs = m_Nonogram->time(); |
|
|
|
|
quint8 seconds = secs % 60; |
|
|
|
|
quint8 minutes = secs / 60; |
|
|
|
|
quint8 hours = minutes / 60; |
|
|
|
|
minutes %= 60; |
|
|
|
|
|
|
|
|
@ -426,59 +270,8 @@ namespace qcross {
|
|
|
|
|
m_Clock->display(time); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void CCrossFieldWidget::execMark(int x, int y, MarkerType & marker) { |
|
|
|
|
if (m_Solved) return; |
|
|
|
|
|
|
|
|
|
switch (marker) { |
|
|
|
|
case CMT_MARKED: |
|
|
|
|
if (m_Picture->solution().pixel(x, y)) { |
|
|
|
|
m_RemainingPixels--; |
|
|
|
|
m_OverlayData[x][y] = marker; |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
m_ErrorCount++; |
|
|
|
|
if (m_ErrorAware) { |
|
|
|
|
m_OverlayData[x][y] = CMT_CROSSED; |
|
|
|
|
marker = CMT_NONE; |
|
|
|
|
m_LastErrorMark.setX(x); |
|
|
|
|
m_LastErrorMark.setY(y); |
|
|
|
|
emit markError(); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
m_OverlayData[x][y] = marker; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case CMT_CROSSED: |
|
|
|
|
case CMT_UNMARKED: |
|
|
|
|
if (m_ErrorAware && x == m_LastErrorMark.x() && y == m_LastErrorMark.y()) { |
|
|
|
|
m_LastErrorMark.setX(-1); |
|
|
|
|