diff --git a/libqnono/CMakeLists.txt b/libqnono/CMakeLists.txt index 1cfac0e..246b583 100644 --- a/libqnono/CMakeLists.txt +++ b/libqnono/CMakeLists.txt @@ -7,14 +7,13 @@ include_directories(${QT_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_S include(${QT_USE_FILE}) set(SOURCES_MOC_H - cnonogramsolver.h + cnonogram.h ccrosspackagemodel.h ccrosspackagelistmodel.h ) set(SOURCES_CPP cnonogram.cpp - cnonogramsolver.cpp ccrosspackage.cpp ccrosspackagemodel.cpp ccrosspackagelistmodel.cpp diff --git a/libqnono/ccrosspackage.cpp b/libqnono/ccrosspackage.cpp index 24e5819..62870cf 100644 --- a/libqnono/ccrosspackage.cpp +++ b/libqnono/ccrosspackage.cpp @@ -21,6 +21,7 @@ #include "nonogramproblem.h" #include #include +#include namespace libqnono { //public: @@ -71,10 +72,12 @@ namespace libqnono { } in >> pictureCount; + QString id(identifier()); + int i; for (i = 0; i < pictureCount && !in.atEnd(); i++) { m_PictureList.append(NonogramProblem()); - if (!m_PictureList.last().readFromStream(in)) { + if (!m_PictureList.last().readFromStream(in, id, i)) { m_PictureList.pop_back(); qCritical("invalid package file - invalid picture"); return false; @@ -174,4 +177,10 @@ namespace libqnono { } return p; } + + QString CCrossPackage::identifierFromPath(const QString &fileName) { + QString id(QDir::toNativeSeparators(fileName).section(QDir::separator(), -1, -1, QString::SectionSkipEmpty)); + while (id.endsWith(".cpk", Qt::CaseInsensitive) || id.endsWith(".hsc", Qt::CaseInsensitive)) id.chop(4); + return id; + } } diff --git a/libqnono/ccrosspackage.h b/libqnono/ccrosspackage.h index 51cc4c5..7adef93 100644 --- a/libqnono/ccrosspackage.h +++ b/libqnono/ccrosspackage.h @@ -37,6 +37,7 @@ namespace libqnono { void setFileName(QString & value) { m_FileName = value; } QString fileName() const { return m_FileName; } + QString identifier() const { return identifierFromPath(m_FileName); } void setName(QString value) { m_Name = value; } QString name() const { return m_Name; } @@ -52,6 +53,9 @@ namespace libqnono { static CCrossPackage * read(QString fileName); static CCrossPackage * readHeader(QString fileName); + /* identifier is basename without extension; the function is idempotent and can be used on identifiers and highscore paths too */ + static QString identifierFromPath(const QString &fileName); + protected: bool doReadHeader(QDataStream & in); bool doReadData(QDataStream & in); diff --git a/libqnono/ccrosspackagemodel.cpp b/libqnono/ccrosspackagemodel.cpp index 638913c..4a3d5aa 100644 --- a/libqnono/ccrosspackagemodel.cpp +++ b/libqnono/ccrosspackagemodel.cpp @@ -21,8 +21,8 @@ #include #include "ccrosspackage.h" -#include "cnonogram.h" #include "ccrosspackagemodel.h" +#include "nonogramproblem.h" #include "constants.h" #define COL_NAME 0 @@ -37,23 +37,15 @@ namespace libqnono { QString result; if (hours) { - if (hours < 10) - result += '0'; - result += QString::number(hours); - result += ':'; + result = QString("%1:").arg(hours, 2, 10, QLatin1Char('0')); } minutes %= 60; - if (minutes < 10) - result += '0'; - result += QString::number(minutes); + result += QString("%1").arg(minutes, 2, 10, QLatin1Char('0')); if (showSeconds) { - result += ':'; - if (strippedSeconds < 10) - result += '0'; - result += QString::number(strippedSeconds); + result += QString(":%1").arg(strippedSeconds, 2, 10, QLatin1Char('0')); } return result; } @@ -93,19 +85,19 @@ namespace libqnono { case COL_NAME: switch (role) { case Qt::DecorationRole: - return static_cast(index.internalPointer())->timeout() ? + return static_cast(index.internalPointer())->timeout() ? QIcon(LIBQCROSS_ICON_TIMEOUT) : QIcon(LIBQCROSS_ICON_TIMETRIAL); case Qt::EditRole: case Qt::DisplayRole: - return static_cast(index.internalPointer())->name(); + return static_cast(index.internalPointer())->name(); default: break; } break; case COL_TIME: if (role == Qt::DisplayRole) - return formatedTime(static_cast(index.internalPointer())->timeout()); + return formatedTime(static_cast(index.internalPointer())->timeout()); break; default: break; diff --git a/libqnono/cnonogram.cpp b/libqnono/cnonogram.cpp index 77ccd0d..d54faec 100644 --- a/libqnono/cnonogram.cpp +++ b/libqnono/cnonogram.cpp @@ -18,46 +18,336 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "cnonogram.h" +#include "nonogramsolver.h" + #include +#include #include namespace libqnono { - static const quint64 CNonogram_MAGIC = Q_UINT64_C(0x35a8bca32006c5a9); + static const char CNonogram_HEADER[] = {'C', 'R', 'S', 'V'}; /* readable magic */ + static const quint64 CNonogram_MAGIC = Q_UINT64_C(0x35a8bca32006c5a9); /* binary magic */ - CNonogram::CNonogram() { + CNonogram::CNonogram(QObject *parent) : QObject(parent), m_markedPixels(0), m_time(0), m_errorCount(0), m_preventErrors(true), m_finished(true), m_paused(true) { } - CNonogram::CNonogram(const NonogramProblem & problem) - : m_problem(problem), m_marker(problem.size()) { + void CNonogram::start(const NonogramProblem & problem) { + m_problem = problem; + m_marker.reset(problem.size()); + m_markedPixels = 0; + m_time = problem.timeout(); + m_errorCount = 0; + m_preventErrors = problem.timeout() > 0; + m_finished = true; + m_paused = true; + + if (!valid()) { + emit loaded(); + emit tick(0); + emit timeup(); + return; + } + internRestart(true); + emit loaded(); } - bool CNonogram::readFromStream(QDataStream & stream) { - quint64 magic; - stream >> magic; - if (CNonogram_MAGIC != magic || QDataStream::Ok != stream.status()) { - if (QDataStream::ReadPastEnd != stream.status()) stream.setStatus(QDataStream::ReadCorruptData); + void CNonogram::solve() { + if (!valid() || m_finished || m_paused) return; + + QList solutions = libqnono::solve(m_problem.numbers()); + if (!solutions.empty()) { + NonogramImage &sol(solutions.first()); + m_errorCount = 0; + //m_time = -1; + m_markedPixels = sol.blackPixels(); + for (int i = 0; i < width(); ++i) { + for (int j = 0; j < height(); ++j) { + NonogramMarker::Mark mark = sol.pixel(i, j) ? NonogramMarker::MARKED : NonogramMarker::CROSSED; + if (mark != m_marker.pixel(i, j)) { + m_marker.setPixel(i, j, mark); + emit changedMark(i, j); + } + } + } + m_finished = true; + m_timer.stop(); + emit won(m_time); + } + } + + bool CNonogram::saveGame(QString fileName) { + qDebug("saving game state file: %s", fileName.toAscii().data()); + QFile file(fileName); + if (!file.open(QIODevice::WriteOnly)) { + qDebug("couldn't open file for writing"); return false; } - NonogramProblem problem; - NonogramMarker marker; + QDataStream out(&file); + out.setVersion(QDataStream::Qt_4_0); - if (!problem.readFromStream(stream)) return false; - if (!marker.readFromStream(stream)) return false; + writeToStream(out); - if (problem.size() != marker.size()) { + return true; + } + + bool CNonogram::loadGame(QString fileName) { + qDebug("opening game state file: %s", fileName.toAscii().data()); + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly)) { + qDebug("couldn't open file for writing: %s", file.errorString().toAscii().data()); + return false; + } + + QDataStream in(&file); + in.setVersion(QDataStream::Qt_4_0); + + if (!readFromStream(in)) { + switch (in.status()) { + case QDataStream::ReadPastEnd: + qDebug("Unexpected end of file"); + break; + case QDataStream::ReadCorruptData: + default: + qDebug("Corrupted save game"); + break; + } + return false; + } + + return true; + } + + bool CNonogram::readFromStream(QDataStream & stream) { + char magicHeader[sizeof(CNonogram_HEADER)]; + stream.readRawData(magicHeader, sizeof(CNonogram_HEADER)); + if (QDataStream::Ok != stream.status()) return false; + if (0 != memcmp(magicHeader, CNonogram_HEADER, sizeof(CNonogram_HEADER))) { + qDebug("Invalid text magic"); stream.setStatus(QDataStream::ReadCorruptData); return false; } + quint64 magic; + stream >> magic; + if (QDataStream::Ok != stream.status()) return false; + if (CNonogram_MAGIC != magic) { + qDebug("Invalid binary magic"); + stream.setStatus(QDataStream::ReadCorruptData); + return false; + } + + QString packageIdentifier; + int packageIndex; + + stream >> packageIdentifier >> packageIndex; + if (QDataStream::Ok != stream.status()) return false; + + NonogramProblem problem; + NonogramMarker marker; + + if (!problem.readFromStream(stream, packageIdentifier, packageIndex)) return false; + if (!marker.readFromStream(stream)) return false; + + if (problem.size() != marker.size()) { + qDebug("Problem size doesn't match maker size"); + stream.setStatus(QDataStream::ReadCorruptData); + return false; + } + + int time, errorCount; + bool preventErrors; + stream >> time >> errorCount >> preventErrors; + if (QDataStream::Ok != stream.status()) return false; + + if (preventErrors && (0 == problem.timeout())) { + stream.setStatus(QDataStream::ReadCorruptData); + return false; + } + + NonogramImage markerImage(marker); + const NonogramImage &solution(problem.solution()); + int markedPixels = markerImage.blackPixels(); + bool finished; + if (preventErrors) { + /* check no wrong mark is set */ + for (int x = 0; x < problem.width(); ++x) { + for (int y = 0; y < problem.height(); ++y) { + if (markerImage.pixel(x, y) && !solution.pixel(x, y)) { + qDebug("Wrong marked pixel and preventErrors is on: %i, %i", x, y); + stream.setStatus(QDataStream::ReadCorruptData); + return false; + } + } + } + finished = (markedPixels == solution.blackPixels()); + } else { + finished = (markedPixels == solution.blackPixels() && problem.numbers().check(markerImage)); + } + m_problem = problem; m_marker = marker; + m_markedPixels = markedPixels; + m_time = time; + m_errorCount = errorCount; + m_preventErrors = preventErrors; + m_finished = finished; + m_paused = false; + + if (time == 0) { + m_finished = true; + emit loaded(); + emit tick(m_time); + emit timeup(); + } else if (finished) { + emit loaded(); + emit tick(m_time); + emit won(m_time); + } else { + m_timer.start(1000, this); + emit tick(m_time); + emit loaded(); + } return true; } void CNonogram::writeToStream(QDataStream & stream) const { - stream << CNonogram_MAGIC << m_problem << m_marker; + stream.writeRawData(CNonogram_HEADER, sizeof(CNonogram_HEADER)); + stream << CNonogram_MAGIC; + /* problem meta data; not stored by m_problem itself */ + stream << m_problem.packageIdentifier() << m_problem.packageIndex(); + stream << m_problem << m_marker; + + stream << m_time << m_errorCount << m_preventErrors; + } + +// public slots + void CNonogram::setMark(int x, int y, NonogramMarker::Mark mark) { + if (x < 0 || x >= width() || y < 0 || y >= height()) return; + if (m_finished || m_paused) return; + + if (m_preventErrors) { + // if pixel already is marked it must be correct - no reason to undo it + if (m_marker.pixel(x, y) == NonogramMarker::MARKED) return; + + if (m_marker.pixel(x, y) == mark) return; /* nothing to change */ + + if (mark == NonogramMarker::MARKED && !m_problem.solution().pixel(x, y)) { + int penalty; + m_marker.setPixel(x, y, NonogramMarker::CROSSED); + ++m_errorCount; + switch (m_errorCount) { + case 1: penalty = 2*60; break; + case 2: penalty = 4*60; break; + default: penalty = 8*60; break; + } + if (penalty >= m_time) { + // lost + m_finished = true; + m_timer.stop(); + m_time = 0; + emit wrongMark(x, y, penalty); + emit changedMark(x, y); + emit tick(m_time); + emit timeup(); + } else { + m_time -= penalty; + emit wrongMark(x, y, penalty); + emit changedMark(x, y); + emit tick(m_time); + } + } else { + // unmarking is prevented above + // if (m_marker.pixel(x, y) == NonogramMarker::MARKED) --m_markedPixels; + + m_marker.setPixel(x, y, mark); + if (mark == NonogramMarker::MARKED) ++m_markedPixels; + + if (m_markedPixels == m_problem.solution().blackPixels()) { + + m_finished = true; + m_timer.stop(); + emit changedMark(x, y); + emit won(m_time); + return; + } + + emit changedMark(x, y); + } + } else { + if (m_marker.pixel(x, y) == mark) return; /* nothing to change */ + + if (m_marker.pixel(x, y) == NonogramMarker::MARKED) --m_markedPixels; + + m_marker.setPixel(x, y, mark); + if (mark == NonogramMarker::MARKED) ++m_markedPixels; + + // blackPixels is an invariant on all solutions for a set of numbers + if (m_markedPixels == m_problem.solution().blackPixels() && m_problem.numbers().check(NonogramImage(m_marker))) { + m_finished = true; + m_timer.stop(); + emit changedMark(x, y); + emit won(m_time); + return; + } + + emit changedMark(x, y); + } + } + + void CNonogram::restart() { + internRestart(false); + } + + void CNonogram::pause() { + if (m_finished || m_paused) return; + m_paused = true; + m_timer.stop(); + emit paused(m_time); + } + + void CNonogram::resume() { + if (m_finished || !m_paused) return; + m_paused = false; + m_timer.start(1000, this); + emit resumed(m_time); + } + +// protected + void CNonogram::timerEvent(QTimerEvent * event) { + if (m_finished) { + m_timer.stop(); + return; + } + m_time = m_time + (timeout() ? -1 : 1); + if (m_time <= 0) m_time = 0; + if (0 == m_time) { + // lost + m_finished = true; + m_timer.stop(); + emit tick(m_time); + emit timeup(); + } else { + emit tick(m_time); + } + } + + void CNonogram::internRestart(bool newGame) { + if (!valid()) { + emit tick(0); + emit timeup(); + return; + } + m_finished = false; + m_errorCount = 0; + m_time = timeout(); + m_marker.reset(); + m_markedPixels = 0; + m_paused = false; + m_timer.start(1000, this); + emit tick(m_time); + if (!newGame) emit restarted(); } QDataStream & operator<<(QDataStream& stream, const libqnono::CNonogram& nonogram) { diff --git a/libqnono/cnonogram.h b/libqnono/cnonogram.h index 8c7a0ea..22a232e 100644 --- a/libqnono/cnonogram.h +++ b/libqnono/cnonogram.h @@ -20,9 +20,11 @@ #ifndef LIBQCROSS_CMONOPICTURE_H #define LIBQCROSS_CMONOPICTURE_H +#include #include #include #include +#include #include "nonogramproblem.h" #include "nonogrammarker.h" @@ -30,12 +32,14 @@ class QImage; namespace libqnono { - class CNonogram { + class CNonogram : public QObject { + Q_OBJECT public: typedef QVector NumbersVector; - CNonogram(); - CNonogram(const NonogramProblem & problem); + explicit CNonogram(QObject *parent = 0); + + void start(const NonogramProblem & problem); const NonogramProblem & problem() const { return m_problem; } QString name() const { return m_problem.name(); } @@ -45,19 +49,59 @@ namespace libqnono { const NonogramMarker & marker() const { return m_marker; } + bool valid() const { return (!size().isEmpty()) && (0 != m_problem.solution().blackPixels()); } + QSize size() const { return m_problem.size(); } int width() const { return size().width(); } int height() const { return size().height(); } - /* returns false if set MARKED on white solution pixel (it still sets the mark) */ - bool setMark(int x, int y, NonogramMarker::Mark mark); + int time() const { return m_time; } + + bool isPaused() const { return m_paused; } + bool isFinished() const { return m_finished; } + + bool saveGame(QString fileName); + bool loadGame(QString fileName); bool readFromStream(QDataStream & stream); void writeToStream(QDataStream& stream) const; + public slots: + void setMark(int x, int y, NonogramMarker::Mark mark); + void restart(); + void pause(); + void resume(); + void solve(); + + signals: + void loaded(); /* new problem/loaded savegame */ + + void won(int score); /* score is the current time */ + void timeup(); + + void wrongMark(int x, int y, int penaltyTime); + void changedMark(int x, int y); + + void restarted(); + void paused(int time); + void resumed(int time); + void tick(int time); + protected: + virtual void timerEvent(QTimerEvent * event); + + void internRestart(bool newGame); + + QBasicTimer m_timer; + NonogramProblem m_problem; NonogramMarker m_marker; + int m_markedPixels; + + int m_time; /* timeout() == 0: used time, timeout() > 0: remaining time */ + int m_errorCount; + bool m_preventErrors; /* (timeout() > 0) for now - must be false if timeout() == 0 */ + bool m_finished, m_paused; }; QDataStream & operator<<(QDataStream & stream, const CNonogram & nonogram); diff --git a/libqnono/cnonogramsolver.cpp b/libqnono/cnonogramsolver.cpp deleted file mode 100644 index eb2b99c..0000000 --- a/libqnono/cnonogramsolver.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "cnonogramsolver.h" -#include "cnonogram.h" - -#include "nonogramsolver.h" - -#include -#include - -namespace libqnono { - CNonogramSolver::CNonogramSolver(QObject * parent) - : QObject(parent), m_Nonogram(0) { - } - - CNonogramSolver::~CNonogramSolver() { - } - - void CNonogramSolver::setNonogram(CNonogram * nonogram) { - m_Nonogram = nonogram; - } - - bool CNonogramSolver::solve() { - if (!m_Nonogram) return false; - - QList solutions = libqnono::solve(m_Nonogram->numbers()); - if (!solutions.empty()) { - NonogramImage &sol(solutions.first()); - for (int i = 0; i < m_Nonogram->width(); ++i) { - for (int j = 0; j < m_Nonogram->height(); ++j) { - emit markRequested(i, j, sol.pixel(i, j) ? CMT_MARKED : CMT_CROSSED); - } - } - return TRUE; - } - - return FALSE; - } -} diff --git a/libqnono/cnonogramsolver.h b/libqnono/cnonogramsolver.h deleted file mode 100644 index 3d34b41..0000000 --- a/libqnono/cnonogramsolver.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef LIBQCROSS_CNONOGRAMSOLVER_H -#define LIBQCROSS_CNONOGRAMSOLVER_H - -#include -#include -#include - -namespace libqnono { - class CNonogram; - - class CNonogramSolver : public QObject { - Q_OBJECT - public: - CNonogramSolver(QObject * parent = 0); - ~CNonogramSolver(); - - void setNonogram(CNonogram * nonogram); - public slots: - bool solve(); - signals: - void markRequested(int x, int y, int type); - protected: - enum MarkerType {CMT_UNMARKED = 0, CMT_MARKED = 1, CMT_CROSSED = 2, CMT_NONE = 3}; - - CNonogram * m_Nonogram; - }; -} - -#endif diff --git a/libqnono/nonogramimage.cpp b/libqnono/nonogramimage.cpp index 8cd32fe..3ba5ed7 100644 --- a/libqnono/nonogramimage.cpp +++ b/libqnono/nonogramimage.cpp @@ -24,34 +24,6 @@ namespace libqnono { static const quint64 NonogramImage_DataStream_MAGIC = Q_UINT64_C(0xe47028650d925b33); - class NonogramImageViewRowColumn : public NonogramImageView { - public: - NonogramImageViewRowColumn(NonogramImage & img) : m_img(img) { } - - virtual bool pixel(int row, int col) const { - return m_img.pixel(col, row); - } - virtual bool & pixel(int row, int col) { - return m_img.pixel(col, row); - } - private: - NonogramImage &m_img; - }; - - class NonogramImageViewColumnRow : public NonogramImageView { - public: - NonogramImageViewColumnRow(NonogramImage & img) : m_img(img) { } - - virtual bool pixel(int col, int row) const { - return m_img.pixel(col, row); - } - virtual bool & pixel(int col, int row) { - return m_img.pixel(col, row); - } - private: - NonogramImage &m_img; - }; - NonogramImage::NonogramImage() : m_size(0,0), m_data(0), m_blackPixels(0) { } @@ -74,6 +46,11 @@ namespace libqnono { load(image); } + NonogramImage::NonogramImage(const NonogramMarker & marker) + : m_size(0, 0), m_data(0), m_blackPixels(0) { + load(marker); + } + NonogramImage::~NonogramImage() { delete [] m_data; m_data = 0; } @@ -127,14 +104,6 @@ namespace libqnono { m_size = size; } - NonogramImageView* NonogramImage::viewRowColumn() { - return new NonogramImageViewRowColumn(*this); - } - - NonogramImageView* NonogramImage::viewColumnRow() { - return new NonogramImageViewColumnRow(*this); - } - bool NonogramImage::readFromStream(QDataStream & stream) { quint64 magic; stream >> magic; diff --git a/libqnono/nonogramimage.h b/libqnono/nonogramimage.h index f8c6865..828bef2 100644 --- a/libqnono/nonogramimage.h +++ b/libqnono/nonogramimage.h @@ -25,24 +25,18 @@ namespace libqnono { class NonogramMarker; - class NonogramImageView { - public: - virtual bool pixel(int coord1, int coord2) const = 0; - virtual bool & pixel(int coord1, int coord2) = 0; - }; - class NonogramImage { public: NonogramImage(); - NonogramImage(QSize size); + explicit NonogramImage(QSize size); NonogramImage(const NonogramImage & other); - NonogramImage(const QImage & image); + explicit NonogramImage(const QImage & image); + explicit NonogramImage(const NonogramMarker & marker); ~NonogramImage(); NonogramImage& operator=(const NonogramImage & other); bool operator==(const NonogramImage & other) const; bool pixel(int x, int y) const { return m_data[y*m_size.width()+x]; } - bool & pixel(int x, int y) { return m_data[y*m_size.width()+x]; } void setPixel(int x, int y, bool value) { m_data[y*m_size.width()+x] = value; } void fill(bool value); @@ -53,9 +47,6 @@ namespace libqnono { int height() const { return m_size.height(); } void resize(QSize size); - NonogramImageView* viewRowColumn(); - NonogramImageView* viewColumnRow(); - bool readFromStream(QDataStream & stream); void writeToStream(QDataStream & stream) const; diff --git a/libqnono/nonogrammarker.cpp b/libqnono/nonogrammarker.cpp index 2d1c621..a1a4ea0 100644 --- a/libqnono/nonogrammarker.cpp +++ b/libqnono/nonogrammarker.cpp @@ -62,6 +62,20 @@ namespace libqnono { return true; } + void NonogramMarker::reset() { + int n = m_size.width() * m_size.height(); + for (int i = 0; i < n; ++i) m_data[i] = NONE; + } + + void NonogramMarker::reset(QSize size) { + delete [] m_data; m_data = 0; + + m_size = size; + int n = m_size.width() * m_size.height(); + m_data = new Mark[n]; + for (int i = 0; i < n; ++i) m_data[i] = NONE; + } + bool NonogramMarker::readFromStream(QDataStream & stream) { quint64 magic; stream >> magic; diff --git a/libqnono/nonogrammarker.h b/libqnono/nonogrammarker.h index d89b5ca..c0d076f 100644 --- a/libqnono/nonogrammarker.h +++ b/libqnono/nonogrammarker.h @@ -29,7 +29,7 @@ namespace libqnono { enum Mark { NONE = 0, MARKED = 1, CROSSED = 2 }; NonogramMarker(); - NonogramMarker(QSize size); + explicit NonogramMarker(QSize size); NonogramMarker(const NonogramMarker& other); ~NonogramMarker(); NonogramMarker& operator=(const NonogramMarker& other); @@ -43,6 +43,9 @@ namespace libqnono { int width() const { return m_size.width(); } int height() const { return m_size.height(); } + void reset(); + void reset(QSize size); + bool readFromStream(QDataStream & stream); void writeToStream(QDataStream & stream) const; diff --git a/libqnono/nonogramnumbers.h b/libqnono/nonogramnumbers.h index 3de5c44..5ae8ff3 100644 --- a/libqnono/nonogramnumbers.h +++ b/libqnono/nonogramnumbers.h @@ -33,8 +33,8 @@ namespace libqnono { NonogramNumbers(); NonogramNumbers(const vv_num & rows, const vv_num & columns); - NonogramNumbers(const NonogramImage & image); - NonogramNumbers(const QImage & image); + explicit NonogramNumbers(const NonogramImage & image); + explicit NonogramNumbers(const QImage & image); void calcFromImage(const NonogramImage & image); diff --git a/libqnono/nonogramproblem.cpp b/libqnono/nonogramproblem.cpp index aea0fbf..9944004 100644 --- a/libqnono/nonogramproblem.cpp +++ b/libqnono/nonogramproblem.cpp @@ -52,7 +52,7 @@ namespace libqnono { m_numbers.calcFromImage(m_solution); } - bool NonogramProblem::readFromStream(QDataStream & stream) { + bool NonogramProblem::readFromStream(QDataStream & stream, QString packageIdentifier, int packageIndex) { quint64 magic; stream >> magic; if (NonogramProblem_MAGIC != magic || QDataStream::Ok != stream.status()) { @@ -70,6 +70,8 @@ namespace libqnono { m_name = name; m_timeout = timeout; m_numbers.calcFromImage(m_solution); + m_PackageIdentifier = packageIdentifier; + m_PackageIndex = packageIndex; return true; } diff --git a/libqnono/nonogramproblem.h b/libqnono/nonogramproblem.h index b4a0c25..3379abf 100644 --- a/libqnono/nonogramproblem.h +++ b/libqnono/nonogramproblem.h @@ -36,6 +36,9 @@ namespace libqnono { const NonogramImage & solution() const { return m_solution; } const NonogramNumbers & numbers() const { return m_numbers; } + QString packageIdentifier() const { return m_PackageIdentifier; } + int packageIndex() const { return m_PackageIndex; } + QSize size() const { return m_solution.size(); } int width() const { return size().width(); } int height() const { return size().height(); } @@ -50,7 +53,7 @@ namespace libqnono { void fill(bool value); void loadFromImage(const NonogramImage & solution); - bool readFromStream(QDataStream & stream); + bool readFromStream(QDataStream & stream, QString packageIdentifier = QString(), int packageIndex = -1); void writeToStream(QDataStream & stream) const; private: @@ -59,6 +62,10 @@ namespace libqnono { QString m_name; quint16 m_timeout; + + /* not saved directly */ + QString m_PackageIdentifier; + int m_PackageIndex; }; QDataStream & operator<<(QDataStream & stream, const NonogramProblem & problem); diff --git a/qcross/ccrossfieldwidget.cpp b/qcross/ccrossfieldwidget.cpp index 9f00fef..94eebf6 100644 --- a/qcross/ccrossfieldwidget.cpp +++ b/qcross/ccrossfieldwidget.cpp @@ -20,7 +20,6 @@ #include "ccrossfieldwidget.h" #include -#include #include #include @@ -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); + + 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))); } CCrossFieldWidget::~CCrossFieldWidget() { - cleanup(); - -// delete m_Clock; - } - - 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(); + 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); - 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); - } - } - 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]); - } - } - //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(type); - - execMark(x, y, marker); - } - - 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::setErrorAware(bool value) { - m_ErrorAware = value; - } - void CCrossFieldWidget::setNumbersMarkable(bool value) { m_NumbersMarkable = value; } - void CCrossFieldWidget::start() { - reset(); - resume(); + //protected slots: + void CCrossFieldWidget::loaded() { + m_LastErrorMark = QPoint(-1, -1); + initialize(); + updateTimeDisplay(); + m_Messages.clear(); + if (m_Nonogram->valid()) { + if (m_Nonogram->time() == m_Nonogram->timeout()) { + showMessage(tr("Game started!"), 1000); + } else { + showMessage(tr("Save game loaded!"), 1000); + } + setEnabled(true); + } else { + nextMessage(); + setEnabled(false); + } } - void CCrossFieldWidget::pause() { - if (m_Solved) - return; - - killTimer(m_TimerId); - m_TimerId = -1; - + void CCrossFieldWidget::won(int score) { + showMessage(tr("Congratulations! You've solved the puzzle.")); + } + + void CCrossFieldWidget::timeup() { + showMessage(tr("Too bad! Time's up."), 0, CCrossFieldWidget::Critical); + } + + 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::changedMark(int x, int y) { + update(); + } + + void CCrossFieldWidget::restarted() { + m_Messages.clear(); + m_LastErrorMark = QPoint(-1, -1); + showMessage(tr("Game restarted."), 1000); + } + + 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); - m_LastErrorMark.setY(-1); - } - - if (m_OverlayData[x][y] == CMT_MARKED) { - if (m_Picture->solution().pixel(x, y)) - m_RemainingPixels++; - else if (!m_ErrorAware) - m_ErrorCount--; - } - - m_OverlayData[x][y] = marker; - break; - default: - break; - } - - if (!m_RemainingPixels && (m_ErrorAware || !m_ErrorCount)) { - killTimer(m_TimerId); - m_TimerId = -1; - m_Paused = true; - m_Solved = true; - emit solved(); - } - } - void CCrossFieldWidget::paintEvent(QPaintEvent *) { - if (!m_Picture) { + if (!m_Nonogram) { return; } @@ -541,23 +334,23 @@ namespace qcross { errorColor.setAlpha(128); painter.setBrush(markerColor); - for (int i = 0; i < m_Picture->width(); i++) { + for (int i = 0; i < m_Nonogram->width(); i++) { originX = m_OffsetX + m_HeaderWidth + i * m_BoxSize; markerRect.moveLeft(originX + m_MarkerOffset); - for (int j = 0; j < m_Picture->height(); j++) { + for (int j = 0; j < m_Nonogram->height(); j++) { originY = m_OffsetY + m_HeaderHeight + j * m_BoxSize; markerRect.moveTop(originY + m_MarkerOffset); - switch (m_OverlayData[i][j]) { - case CMT_MARKED: + switch (m_Nonogram->marker().pixel(i, j)) { + case NonogramMarker::MARKED: painter.fillRect(markerRect, painter.brush()); break; - case CMT_CROSSED: - if (m_Solved) + case NonogramMarker::CROSSED: + if (m_Nonogram->isFinished()) break; - if (m_ErrorAware && m_ErrorCount && i == m_LastErrorMark.x() && j == m_LastErrorMark.y()) { + if (i == m_LastErrorMark.x() && j == m_LastErrorMark.y()) { painter.setBrush(errorColor); painter.fillRect(markerRect, painter.brush()); painter.setBrush(markerColor); @@ -585,7 +378,7 @@ namespace qcross { } // draw numbers area - if (m_Paused) + if (m_Nonogram->isPaused()) painter.setPen(palette().color(QPalette::Shadow)); QFont font = painter.font(); @@ -593,13 +386,13 @@ namespace qcross { painter.setFont(font); - for (int i = 0; i < m_Picture->width(); i++) { + for (int i = 0; i < m_Nonogram->width(); i++) { originX = m_OffsetX + m_HeaderWidth + i * m_BoxSize; painter.fillRect(originX, m_OffsetY, m_BoxSize, m_HeaderHeight, palette().color((i % 2) ? QPalette::AlternateBase : QPalette::Base)); - if (!m_Paused) { + if (!m_Nonogram->isPaused()) { painter.setPen(palette().color(QPalette::WindowText)); - int j = m_Picture->numbers().columns()[i].count();; - foreach (quint16 block, m_Picture->numbers().columns()[i]) { + int j = m_Nonogram->numbers().columns()[i].count();; + foreach (quint16 block, m_Nonogram->numbers().columns()[i]) { originY = m_OffsetY + m_HeaderHeight - j * m_BoxSize; painter.drawText(originX, originY, m_BoxSize, m_BoxSize, @@ -613,13 +406,13 @@ namespace qcross { } // painter.drawLine(m_OffsetX + m_RasterWidth, m_OffsetY, m_OffsetX + m_RasterWidth, m_OffsetY + m_RasterHeight); - for (int i = 0; i < m_Picture->height(); i++) { + for (int i = 0; i < m_Nonogram->height(); i++) { originY = m_OffsetY + m_HeaderHeight + i * m_BoxSize; painter.fillRect(m_OffsetX, originY, m_HeaderWidth, m_BoxSize, palette().color((i % 2) ? QPalette::AlternateBase : QPalette::Base)); - if (!m_Paused) { + if (!m_Nonogram->isPaused()) { painter.setPen(palette().color(QPalette::WindowText)); - int j = m_Picture->numbers().rows()[i].count(); - foreach (quint16 block, m_Picture->numbers().rows()[i]) { + int j = m_Nonogram->numbers().rows()[i].count(); + foreach (quint16 block, m_Nonogram->numbers().rows()[i]) { originX = m_OffsetX + m_HeaderWidth - j * m_BoxSize; painter.drawText(originX, originY, m_BoxSize, m_BoxSize, Qt::AlignVCenter | Qt::AlignCenter, QString::number(block)); @@ -666,19 +459,16 @@ namespace qcross { }*/ void CCrossFieldWidget::resizeEvent(QResizeEvent * /*event*/) { - if (!m_Picture) - return; - updateMetrics(); } void CCrossFieldWidget::updateMetrics() { - m_HeaderWidth = max(m_Picture->numbers().maximumNumberCount()+1, 5); + m_HeaderWidth = max(m_Nonogram->numbers().maximumNumberCount()+1, 5); /* m_HeaderWidth = max(m_Picture->width() / 2 + 1, m_Picture->height() / 2 + 1); m_HeaderWidth = m_Picture->width() / 2 + 1; m_HeaderHeight = m_Picture->height() / 2 + 1;*/ - int fieldsize = min((m_Picture->width() + m_HeaderWidth), (m_Picture->height() + m_HeaderWidth)); + int fieldsize = min((m_Nonogram->width() + m_HeaderWidth), (m_Nonogram->height() + m_HeaderWidth)); int widgetsize = min(width(), height()); m_BoxSize = ((double)widgetsize / fieldsize); @@ -690,8 +480,8 @@ namespace qcross { m_HeaderWidth *= m_BoxSize; m_HeaderHeight = m_HeaderWidth; - m_RasterWidth = m_BoxSize * m_Picture->width() + m_HeaderWidth; - m_RasterHeight = m_BoxSize * m_Picture->height() + m_HeaderHeight; + m_RasterWidth = m_BoxSize * m_Nonogram->width() + m_HeaderWidth; + m_RasterHeight = m_BoxSize * m_Nonogram->height() + m_HeaderHeight; m_OffsetX = (width() - m_RasterWidth) / 2; m_OffsetY = (height() - m_RasterHeight) / 2; @@ -702,39 +492,36 @@ namespace qcross { m_Clock->setGeometry(m_OffsetX, m_OffsetY, m_HeaderWidth, clockHeight); // if (m_Notifier && m_Notifier->isVisible()) // m_Notifier->setGeometry(m_OffsetX, m_OffsetY + clockHeight, m_HeaderWidth, m_Notifier->sizeHint().height()); - } - - void CCrossFieldWidget::mousePressEvent(QMouseEvent * event) { - if (m_Paused) - return; - - int pressedX = event->x() - m_OffsetX; - int pressedY = event->y() - m_OffsetY; - - if (pressedX < m_HeaderWidth || pressedY < m_HeaderHeight || pressedX >= m_RasterWidth || pressedY >= m_RasterHeight) - return; - - pressedX = (pressedX - m_HeaderWidth) / m_BoxSize; - pressedY = (pressedY - m_HeaderHeight) / m_BoxSize; - - - if (event->button() == Qt::RightButton) - m_MouseMark = CMT_CROSSED; - else - m_MouseMark = CMT_MARKED; - - if (m_OverlayData[pressedX][pressedY] == m_MouseMark) - m_MouseMark = CMT_UNMARKED; - - execMark(pressedX, pressedY, m_MouseMark); update(); } - void CCrossFieldWidget::mouseMoveEvent(QMouseEvent * event) { - if (m_Paused) + void CCrossFieldWidget::mousePressEvent(QMouseEvent * event) { + int pressedX = event->x() - m_OffsetX; + int pressedY = event->y() - m_OffsetY; + + if (pressedX < m_HeaderWidth || pressedY < m_HeaderHeight || pressedX >= m_RasterWidth || pressedY >= m_RasterHeight) return; - if (m_MouseMark == CMT_NONE) + pressedX = (pressedX - m_HeaderWidth) / m_BoxSize; + pressedY = (pressedY - m_HeaderHeight) / m_BoxSize; + + m_MouseLastX = pressedX; m_MouseLastY = pressedY; + + if (event->button() == Qt::RightButton) + m_MouseMark = NonogramMarker::CROSSED; + else + m_MouseMark = NonogramMarker::MARKED; + + m_MouseDown = true; + + if (m_Nonogram->marker().pixel(pressedX, pressedY) == m_MouseMark) + m_MouseMark = NonogramMarker::NONE; + + m_Nonogram->setMark(pressedX, pressedY, m_MouseMark); + } + + void CCrossFieldWidget::mouseMoveEvent(QMouseEvent * event) { + if (!m_MouseDown) return; int pressedX = event->x() - m_OffsetX; @@ -746,13 +533,13 @@ namespace qcross { pressedX = (pressedX - m_HeaderWidth) / m_BoxSize; pressedY = (pressedY - m_HeaderHeight) / m_BoxSize; - if (m_OverlayData[pressedX][pressedY] != m_MouseMark) { - execMark(pressedX, pressedY, m_MouseMark); - update(); - } + if (pressedX == m_MouseLastX && pressedY == m_MouseLastY) return; + m_MouseLastX = pressedX; m_MouseLastY = pressedY; + + m_Nonogram->setMark(pressedX, pressedY, m_MouseMark); } void CCrossFieldWidget::mouseReleaseEvent(QMouseEvent *) { - m_MouseMark = CMT_NONE; + m_MouseDown = false; } } diff --git a/qcross/ccrossfieldwidget.h b/qcross/ccrossfieldwidget.h index 60be903..f97fb27 100644 --- a/qcross/ccrossfieldwidget.h +++ b/qcross/ccrossfieldwidget.h @@ -23,6 +23,8 @@ #include #include +#include + class QLCDNumber; class QFrame; class QLabel; @@ -33,47 +35,36 @@ namespace libqnono { } namespace qcross { - enum MarkerType {CMT_UNMARKED = 0, CMT_MARKED = 1, CMT_CROSSED = 2, CMT_NONE = 3}; - class CCrossFieldWidget : public QWidget { Q_OBJECT public: enum MessageType {Information = 1, Warning = 2, Critical = 3, Invalid = 0}; - bool isPaused() const { return m_Paused; } - bool isSolved() const { return m_Solved; } - bool isErrorAware() const { return m_ErrorAware; } - - int time() const { return m_Time; } - qint32 errorCount() const { return m_ErrorCount; } - - CCrossFieldWidget(libqnono::CNonogram * picture, QWidget * parent = 0); + CCrossFieldWidget(QWidget * parent = 0); ~CCrossFieldWidget(); - QPoint lastErrorMark() const { return m_LastErrorMark; } - - void setPicture(libqnono::CNonogram * picture); + libqnono::CNonogram * nonogram() { return m_Nonogram; } void showMessage(const QString message = QString(), int timeout = 0, MessageType type = Information); - void applyState(QDataStream & stream); - void dumpState(QDataStream & stream); - public slots: - void mark(int x, int y, int type); - void setTime(int value); - void setErrorAware(bool value); void setNumbersMarkable(bool value); - void start(); - void pause(); - void resume(); - signals: - void markError(); - void solved(); - void timeUp(); - void timeChanged(int value); - + protected slots: + /* signals from nonogram */ + void loaded(); + + void won(int score); + void timeup(); + + void wrongMark(int x, int y, int penaltyTime); + void changedMark(int x, int y); + + void restarted(); + void paused(int time); + void resumed(int time); + void tick(int time); + protected: struct Message { MessageType type; @@ -84,10 +75,10 @@ namespace qcross { }; QQueue m_Messages; + int m_MessageTimeoutId; + Message m_Message; - libqnono::CNonogram * m_Picture; - MarkerType ** m_OverlayData; - quint32 m_RemainingPixels; + libqnono::CNonogram * m_Nonogram; int m_BoxSize; qreal m_MarkerSize; @@ -99,15 +90,11 @@ namespace qcross { int m_RasterWidth; int m_RasterHeight; - MarkerType m_MouseMark; + libqnono::NonogramMarker::Mark m_MouseMark; + bool m_MouseDown; + int m_MouseLastX, m_MouseLastY; - bool m_ErrorAware; bool m_NumbersMarkable; - int m_Time; - bool m_Paused; - bool m_Solved; - int m_TimerId; - int m_MessageTimeoutId; QLCDNumber * m_Clock; @@ -115,22 +102,14 @@ namespace qcross { // QLabel * m_NotifierIcon; // QLabel * m_NotifierText; - qint32 m_ErrorCount; QPoint m_LastErrorMark; - Message m_Message; void nextMessage(); - inline void initialize(); - inline void cleanup(); - inline void reset(); - - inline bool checkNoError(int x, int y); + void initialize(); /** update metrics for new problem */ void timerEvent(QTimerEvent * event); - inline void updateTimeDisplay(); - - inline void execMark(int x, int y, MarkerType & marker); + void updateTimeDisplay(); void paintEvent(QPaintEvent * event); @@ -138,7 +117,7 @@ namespace qcross { */ void resizeEvent(QResizeEvent * event); - void updateMetrics(); + void updateMetrics(); /** update metrics after resize */ void mousePressEvent(QMouseEvent * event); void mouseMoveEvent(QMouseEvent * event); diff --git a/qcross/cgamewindow.cpp b/qcross/cgamewindow.cpp index 9ff7796..e2c208f 100644 --- a/qcross/cgamewindow.cpp +++ b/qcross/cgamewindow.cpp @@ -29,7 +29,6 @@ #include #include -#include #include #include "constants.h" @@ -42,32 +41,24 @@ namespace qcross { using namespace libqnono; //public CGameWindow::CGameWindow(QWidget * parent) : QMainWindow(parent) { - m_Highscore = NULL; - m_PictureIndex = -1; - m_Picture = NULL; - -// CNonogram * dummyPic = new CNonogram(QSize(10, 10)); -// dummyPic->updateNumbers(); - - m_Field = new CCrossFieldWidget(NULL, this); -// m_Field->setTime(42 * 60 + 23); + m_Field = new CCrossFieldWidget(this); + m_Nonogram = m_Field->nonogram(); setCentralWidget(m_Field); m_Field->showMessage(tr("Welcome to QCross!")); createActions(); -// statusBar()->show(); - m_Solver = new CNonogramSolver(this); - connect(m_Solver, SIGNAL(markRequested(int, int, int)), m_Field, SLOT(mark(int, int, int))); - connect(m_Field, SIGNAL(solved()), this, SLOT(wonGame())); - connect(m_Field, SIGNAL(timeUp()), this, SLOT(lostGame())); - connect(m_Field, SIGNAL(markError()), this, SLOT(handleErrorMark())); + connect(m_Nonogram, SIGNAL(won(int)), this, SLOT(wonGame(int))); + connect(m_Nonogram, SIGNAL(timeup()), this, SLOT(lostGame())); + + connect(m_Nonogram, SIGNAL(loaded()), SLOT(updateStates())); + connect(m_Nonogram, SIGNAL(restarted()), SLOT(updateStates())); + connect(m_Nonogram, SIGNAL(paused(int)), SLOT(updateStates())); + connect(m_Nonogram, SIGNAL(resumed(int)), SLOT(updateStates())); } CGameWindow::~CGameWindow() { - m_Field->setPicture(NULL); - delete m_Picture; } //protected @@ -83,7 +74,7 @@ namespace qcross { m_SaveGameAction->setEnabled(false); currentMenu->addAction(tr("&Load..."), this, SLOT(loadGame()), Qt::CTRL + Qt::Key_N); currentMenu->addSeparator(); - m_RestartGameAction = currentMenu->addAction(tr("&Restart"), this, SLOT(restartGame()), Qt::CTRL + Qt::Key_R); + m_RestartGameAction = currentMenu->addAction(tr("&Restart"), m_Nonogram, SLOT(restart()), Qt::CTRL + Qt::Key_R); m_RestartGameAction->setEnabled(false); m_PauseGameAction = currentMenu->addAction(tr("&Pause")); m_PauseGameAction->setEnabled(false); @@ -93,7 +84,7 @@ namespace qcross { currentMenu->addSeparator(); currentMenu->addAction(tr("&Quit"), this, SLOT(close()), Qt::CTRL + Qt::Key_Q); currentMenu->addSeparator(); - currentMenu->addAction(tr("debug: solve"), this, SLOT(startSolver())); + currentMenu->addAction(tr("debug: solve"), m_Nonogram, SLOT(solve())); currentToolBar = addToolBar(currentMenu->title()); currentToolBar->addActions(currentMenu->actions()); @@ -104,242 +95,95 @@ namespace qcross { currentMenu->addAction(tr("About &Qt"), qApp, SLOT(aboutQt())); } - const char magicSaveGameHeader[] = {'C', 'R', 'S', 'V'}; - - bool CGameWindow::readSaveGame(QDataStream & stream) { - QString stringBuffer; - qint32 intBuffer; - QSize sizeBuffer; - - // picture index - stream >> intBuffer; qDebug("picture index = %i", m_PictureIndex); - if (stream.atEnd()) { - qCritical("invalid savegame"); - return false; - } - m_PictureIndex = intBuffer; - - // package name - if (m_PictureIndex > -1) { - stream >> stringBuffer; qDebug("package name = %s", qPrintable(stringBuffer)); - if (stream.atEnd()) { - qCritical("invalid savegame"); - return false; - } - m_PackageName = stringBuffer; - - stream >> stringBuffer; qDebug("highscoreFileName = %s", qPrintable(stringBuffer)); - if (stream.atEnd()) { - qCritical("invalid savegame"); - return false; - } - - if (m_Highscore) - delete m_Highscore; - - m_Highscore = new CHighscore(0); - m_Highscore->setFileName(QCROSS_STRING_DATAPATH + QDir::separator() + stringBuffer); - m_Highscore->open(); - } - - // picture - if (m_Picture) - delete m_Picture; - - m_Picture = new CNonogram(); - - if (!m_Picture->readFromStream(stream)) { - qCritical("invalid savegame"); - return false; - } - - // TODO handle save game porting properly - // TODO check for matching nonogram - - m_Field->setPicture(m_Picture); - m_Field->applyState(stream); - - return true; - } - - void CGameWindow::writeSaveGame(QDataStream & stream) { - // picture index - stream << qint32(m_PictureIndex); - if (m_PictureIndex > -1) { - stream << m_PackageName; - stream << m_Highscore->fileName().section(QDir::separator(), -1); - } - - m_Picture->writeToStream(stream); - m_Field->dumpState(stream); - } - void CGameWindow::newGame() { - bool notPaused = !m_Field->isPaused(); + bool notPaused = !m_Nonogram->isPaused(); if (notPaused) - m_Field->pause(); + m_Nonogram->pause(); CNewGameDialog dialog; if (dialog.exec() == QDialog::Accepted) { - if (m_Highscore) - delete m_Highscore; - - m_Highscore = dialog.takeHighscore(); - m_PackageName = dialog.selectedPackageName(); - m_PictureIndex = m_Highscore ? dialog.nonogramIndex() : -1; - - CNonogram * newPicture = dialog.takeNonogram(); - - m_SaveGameAction->setEnabled(true); - m_PauseGameAction->setEnabled(true); - m_RestartGameAction->setEnabled(true); - - m_Field->setPicture(newPicture); - - if (m_Picture) - delete m_Picture; - - m_Picture = newPicture; - - m_Field->resume(); - m_Field->showMessage(tr("Game started!"), 1000); + m_Nonogram->start(dialog.getProblem()); + return; } - if (m_Picture && !m_PauseGameAction->isChecked()) - m_Field->resume(); + if (notPaused) + m_Nonogram->resume(); } void CGameWindow::saveGame() { - if (!m_Picture) - return; - - if (!m_Field->isPaused()) - m_Field->pause(); + bool notPaused = !m_Nonogram->isPaused(); + if (notPaused) + m_Nonogram->pause(); QString fileName = QFileDialog::getSaveFileName(this, tr("Save current game"), QDir::homePath(), tr("QCross Saved games (*.csg)")); - qDebug("saving game state file: %s", fileName.toAscii().data()); - QFile file(fileName); - if (!file.open(QIODevice::WriteOnly)) - return; + m_Nonogram->saveGame(fileName); - QDataStream out(&file); - out.setVersion(QDataStream::Qt_4_0); - - if (out.writeRawData(magicSaveGameHeader, 4) == -1) - qDebug("could not write magic save game header"); - else - writeSaveGame(out); - - if(!m_PauseGameAction->isChecked()) - m_Field->resume(); + if (notPaused) + m_Nonogram->resume(); } void CGameWindow::loadGame() { - if (!m_Field->isPaused()) - m_Field->pause(); + bool notPaused = !m_Nonogram->isPaused(); + if (notPaused) + m_Nonogram->pause(); QString fileName = QFileDialog::getOpenFileName(this, tr("Open saved game"), QDir::homePath(), tr("QCross Saved games (*.csg)")); - qDebug("opening game state file: %s", fileName.toAscii().data()); - QFile file(fileName); - if (!file.open(QIODevice::ReadOnly)) + if (m_Nonogram->loadGame(fileName)) { return; - - QDataStream in(&file); - in.setVersion(QDataStream::Qt_4_0); - - char magicHeader[4]; - in.readRawData(magicHeader, 4); - - qDebug("checking magic savegame header"); - for (int i = 0; i < 4; i++) { - if (magicHeader[i] != magicSaveGameHeader[i]) - return; } - if (readSaveGame(in)) { - m_PauseGameAction->setEnabled(true); - m_PauseGameAction->setChecked(m_Field->isPaused()); - m_SaveGameAction->setEnabled(true); - } - else { - m_Field->setPicture(NULL); - m_PictureIndex = -1; - - if (m_Picture) { - delete m_Picture; - m_Picture = NULL; - } - - if (m_Highscore) { - delete m_Highscore; - m_Highscore = NULL; - } - } - - if (m_Picture && !m_PauseGameAction->isChecked()) - m_Field->resume(); - } - - void CGameWindow::restartGame() { - m_Field->setTime(m_Picture->timeout()); - - m_PauseGameAction->setChecked(false); - m_Field->start(); - - m_Field->showMessage(tr("Game restarted."), 1000); + if (notPaused) + m_Nonogram->resume(); } void CGameWindow::pauseGame(bool value) { - if (value == m_Field->isPaused()) + if (value == m_Nonogram->isPaused()) return; if (value) { - m_Field->pause(); - m_Field->showMessage(tr("Game paused.")); + m_Nonogram->pause(); } else { - m_Field->showMessage(tr("Game resumed."), 1000); - m_Field->resume(); + m_Nonogram->resume(); } } - void CGameWindow::wonGame() { + void CGameWindow::wonGame(int score) { m_PauseGameAction->setEnabled(false); - m_Field->showMessage(tr("Congratulations! You've solved the puzzle.")); - if (m_Highscore) { - qDebug("attempting to save highscore"); - (*m_Highscore)[m_PictureIndex] = m_Field->time(); - m_Highscore->save(); + if (score < 0) return; + const NonogramProblem &problem(m_Nonogram->problem()); + if (!problem.packageIdentifier().isEmpty() && problem.packageIndex() >= 0) { + CHighscore highscore; + highscore.setPackageIdentifier(problem.packageIdentifier()); + if (highscore.open()) { + int oldScore = highscore[problem.packageIndex()]; + if (0 == oldScore || (problem.timeout() > 0 ? score > oldScore : score < oldScore)) { + qDebug("attempting to save highscore"); + highscore[problem.packageIndex()] = score; + highscore.save(); + } + } } } void CGameWindow::lostGame() { m_PauseGameAction->setEnabled(false); - m_Field->showMessage(tr("Too bad! Time's up."), 0, CCrossFieldWidget::Critical); - } - - void CGameWindow::handleErrorMark() { - int timeDiff = (m_Field->errorCount() == 1) ? 2 : ((m_Field->errorCount() == 2) ? 4 : 8); - - m_Field->showMessage(tr("Sorry this was not correct: -%1min").arg(timeDiff), 1000, CCrossFieldWidget::Warning); - - m_Field->setTime(m_Field->time() - timeDiff*60); } void CGameWindow::about() { QMessageBox::about(this, tr("About"), tr("This is a still unfancy gui for solving nonograms.")); } - void CGameWindow::startSolver() { - m_Solver->setNonogram(m_Picture); - - restartGame(); - - m_Solver->solve(); + void CGameWindow::updateStates() { + bool valid = m_Nonogram->valid(); + m_SaveGameAction->setEnabled(valid); + m_PauseGameAction->setEnabled(valid); + m_RestartGameAction->setEnabled(valid); + m_PauseGameAction->setChecked(m_Nonogram->isPaused()); } } diff --git a/qcross/cgamewindow.h b/qcross/cgamewindow.h index ac0c1c1..9708f43 100644 --- a/qcross/cgamewindow.h +++ b/qcross/cgamewindow.h @@ -41,14 +41,8 @@ namespace qcross { ~CGameWindow(); protected: - libqnono::CNonogramSolver * m_Solver; - CCrossFieldWidget * m_Field; - libqnono::CNonogram * m_Picture; - - QString m_PackageName; - int m_PictureIndex; - CHighscore * m_Highscore; + libqnono::CNonogram * m_Nonogram; QAction * m_SaveGameAction; QAction * m_RestartGameAction; @@ -56,26 +50,20 @@ namespace qcross { void createActions(); - bool readSaveGame(QDataStream & stream); - void writeSaveGame(QDataStream & stream); - protected slots: void newGame(); void saveGame(); void loadGame(); - void restartGame(); void pauseGame(bool value); - void wonGame(); + void wonGame(int score); void lostGame(); - void handleErrorMark(); - void about(); - void startSolver(); + void updateStates(); }; } diff --git a/qcross/chighscore.cpp b/qcross/chighscore.cpp index 3ea3fa1..595b40c 100644 --- a/qcross/chighscore.cpp +++ b/qcross/chighscore.cpp @@ -17,10 +17,14 @@ * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ -#include -#include #include "chighscore.h" +#include "constants.h" +#include + +#include +#include +#include namespace qcross { CHighscore::CHighscore(int initialSize) : QList() { @@ -28,12 +32,18 @@ namespace qcross { append(0); } + void CHighscore::setPackageIdentifier(QString PackageIdentifier) { + m_PackageIdentifier = libqnono::CCrossPackage::identifierFromPath(PackageIdentifier); + } + bool CHighscore::open() { - if (m_FileName.isEmpty()) + if (m_PackageIdentifier.isEmpty()) return false; - qDebug("reading highscore file: %s", m_FileName.toAscii().data()); - QFile file(m_FileName); + QString fileName = (QCROSS_STRING_DATAPATH + QDir::separator() + m_PackageIdentifier + ".hsc"); + + qDebug("reading highscore file: %s", fileName.toAscii().data()); + QFile file(fileName); if (!file.open(QIODevice::ReadOnly)) return false; @@ -55,11 +65,13 @@ namespace qcross { } bool CHighscore::save() { - if (m_FileName.isEmpty()) + if (m_PackageIdentifier.isEmpty()) return false; - qDebug("saving highcore file: %s", m_FileName.toAscii().data()); - QFile file(m_FileName); + QString fileName = (QCROSS_STRING_DATAPATH + QDir::separator() + m_PackageIdentifier + ".hsc"); + + qDebug("saving highcore file: %s", fileName.toAscii().data()); + QFile file(fileName); if (!file.open(QIODevice::WriteOnly)) return false; diff --git a/qcross/chighscore.h b/qcross/chighscore.h index 106cf97..ba132d6 100644 --- a/qcross/chighscore.h +++ b/qcross/chighscore.h @@ -31,13 +31,13 @@ namespace qcross { public: CHighscore(int size = 0); - void setFileName(QString value) { m_FileName = value; } - QString fileName() const { return m_FileName; } + void setPackageIdentifier(QString PackageIdentifier); + QString packageIdentifier() const { return m_PackageIdentifier; } bool open(); bool save(); protected: - QString m_FileName; + QString m_PackageIdentifier; }; } diff --git a/qcross/cnewgamedialog.cpp b/qcross/cnewgamedialog.cpp index 054fdec..82aa16a 100644 --- a/qcross/cnewgamedialog.cpp +++ b/qcross/cnewgamedialog.cpp @@ -41,7 +41,7 @@ namespace qcross { CNewGameDialog::CNewGameDialog(QWidget * parent, Qt::WindowFlags f) : QDialog(parent, f), m_Highscore(NULL), - m_Nonogram(NULL) + m_Problem(NULL) { ui.setupUi(this); ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); @@ -79,8 +79,8 @@ namespace qcross { if (m_Highscore) delete m_Highscore; - if (m_Nonogram) - delete m_Nonogram; + if (m_Problem) + delete m_Problem; } /* libqnono::CNonogram * CNewGameDialog::selectedNonogramData() const { @@ -94,45 +94,29 @@ namespace qcross { } libqnono::CCrossPackage * CNewGameDialog::selectedPackage() const { - if (m_Nonogram) return NULL; + if (m_Problem) return NULL; QModelIndex selected = ui.packageList->selectionModel()->selectedIndexes()[0]; return static_cast(selected.internalPointer()); } QString CNewGameDialog::selectedPackageName() const { - if (m_Nonogram) return QString(); + if (m_Problem) return QString(); libqnono::CCrossPackage *p = selectedPackage(); return p ? p->name() : QString(); } - libqnono::CNonogram * CNewGameDialog::takeNonogram() { - libqnono::CNonogram * result; - - if (m_Nonogram) { - result = m_Nonogram; - m_Nonogram = NULL; + NonogramProblem CNewGameDialog::getProblem() { + if (m_Problem) { + return *m_Problem; } else { QModelIndexList selected = ui.packageList->selectionModel()->selectedIndexes(); - if (selected.isEmpty()) - result = NULL; - else { - result = new CNonogram(static_cast(selected[0].internalPointer())->getPicture(nonogramIndex())); - m_PicModel->setPackage(NULL); + if (!selected.isEmpty()) { + return selectedPackage()->getPicture(nonogramIndex()); } } - return result; - } - - CHighscore * CNewGameDialog::takeHighscore() { - if (m_Nonogram) - return NULL; - - CHighscore * result = m_Highscore; - m_Highscore = NULL; - - return result; + return NonogramProblem(); } //protected: @@ -163,16 +147,13 @@ namespace qcross { QString fileName = QFileDialog::getOpenFileName(this, tr("Select a picture to open"), QString(), tr("Images (*.png *.xpm *.xbm *.jpg)")); if (!fileName.isEmpty()) { - if (m_Nonogram) - delete m_Nonogram; + delete m_Problem; m_Problem = 0; QImage image(fileName); if (!image.isNull()) { - m_Nonogram = new CNonogram(NonogramProblem(NonogramImage(image))); + m_Problem = new NonogramProblem(NonogramImage(image)); accept(); } - else - m_Nonogram = NULL; } } @@ -187,7 +168,7 @@ namespace qcross { if (!m_Highscore) m_Highscore = new CHighscore(0); - m_Highscore->setFileName(getHighscoreFileName(package->fileName())); + m_Highscore->setPackageIdentifier(package->identifier()); if (!m_Highscore->open()) { qDebug("opening highscore file failed. will create a new one when nonogram is solved"); m_Highscore->clear(); @@ -197,6 +178,7 @@ namespace qcross { m_PicModel->setHighscore(m_Highscore); } void CNewGameDialog::handlePictureSelectionChanged(const QItemSelection & selected, const QItemSelection &) { + delete m_Problem; m_Problem = 0; ui.buttonBox->button(QDialogButtonBox::Ok)->setDisabled(selected.isEmpty()); } } diff --git a/qcross/cnewgamedialog.h b/qcross/cnewgamedialog.h index a3e1aa8..799d18d 100644 --- a/qcross/cnewgamedialog.h +++ b/qcross/cnewgamedialog.h @@ -26,6 +26,7 @@ namespace libqnono { class CNonogram; class CCrossPackage; + class NonogramProblem; } namespace qcross { @@ -46,15 +47,14 @@ namespace qcross { libqnono::CCrossPackage * selectedPackage() const; QString selectedPackageName() const; - libqnono::CNonogram * takeNonogram(); - CHighscore * takeHighscore(); + libqnono::NonogramProblem getProblem(); protected slots: void importPackage(); void openPictureFile(); private: Ui::picselect ui; CHighscore * m_Highscore; - libqnono::CNonogram * m_Nonogram; /* if != NULL package wasn't used */ + libqnono::NonogramProblem * m_Problem; /* if != NULL package wasn't used */ CMaskedCrossPackageModel * m_PicModel; CMaskedCrossPackageProxyModel * m_PicProxyModel; private slots: diff --git a/qcross/common.cpp b/qcross/common.cpp index ae4c852..cfa1087 100644 --- a/qcross/common.cpp +++ b/qcross/common.cpp @@ -27,32 +27,15 @@ QString formatedTime(quint32 seconds, bool showSeconds) { QString result; if (hours) { - if (hours < 10) - result += '0'; - result += QString::number(hours); - result += ':'; + result = QString("%1:").arg(hours, 2, 10, QLatin1Char('0')); } minutes %= 60; - if (minutes < 10) - result += '0'; - result += QString::number(minutes); + result += QString("%1").arg(minutes, 2, 10, QLatin1Char('0')); if (showSeconds) { - result += ':'; - if (strippedSeconds < 10) - result += '0'; - result += QString::number(strippedSeconds); + result += QString(":%1").arg(strippedSeconds, 2, 10, QLatin1Char('0')); } return result; } - -QString getHighscoreFileName(QString packageFileName) { - if (packageFileName.isEmpty()) - return QString(); - - int tagPosition = packageFileName.lastIndexOf('.'); - - return ((tagPosition == -1) ? packageFileName : packageFileName.left(tagPosition)) + ".hsc"; -} diff --git a/qcross/common.h b/qcross/common.h index ea9a201..f40a553 100644 --- a/qcross/common.h +++ b/qcross/common.h @@ -20,4 +20,3 @@ #include QString formatedTime(quint32 seconds, bool showSeconds = false); -QString getHighscoreFileName(QString packageFileName);