summaryrefslogtreecommitdiffstats
path: root/libksirtet/base
diff options
context:
space:
mode:
Diffstat (limited to 'libksirtet/base')
-rw-r--r--libksirtet/base/Makefile.am16
-rw-r--r--libksirtet/base/README1
-rw-r--r--libksirtet/base/baseprefs.kcfgc7
-rw-r--r--libksirtet/base/board.cpp429
-rw-r--r--libksirtet/base/board.h134
-rw-r--r--libksirtet/base/factory.cpp52
-rw-r--r--libksirtet/base/factory.h60
-rw-r--r--libksirtet/base/field.cpp162
-rw-r--r--libksirtet/base/field.h66
-rw-r--r--libksirtet/base/gtetris.cpp241
-rw-r--r--libksirtet/base/gtetris.h178
-rw-r--r--libksirtet/base/highscores.cpp19
-rw-r--r--libksirtet/base/highscores.h13
-rw-r--r--libksirtet/base/inter.cpp15
-rw-r--r--libksirtet/base/inter.h23
-rw-r--r--libksirtet/base/kzoommainwindow.cpp115
-rw-r--r--libksirtet/base/kzoommainwindow.h128
-rw-r--r--libksirtet/base/libksirtet1.kcfg38
-rw-r--r--libksirtet/base/main.cpp131
-rw-r--r--libksirtet/base/main.h49
-rw-r--r--libksirtet/base/piece.cpp274
-rw-r--r--libksirtet/base/piece.h155
-rw-r--r--libksirtet/base/settings.cpp84
-rw-r--r--libksirtet/base/settings.h33
24 files changed, 2423 insertions, 0 deletions
diff --git a/libksirtet/base/Makefile.am b/libksirtet/base/Makefile.am
new file mode 100644
index 00000000..bb8b2365
--- /dev/null
+++ b/libksirtet/base/Makefile.am
@@ -0,0 +1,16 @@
+INCLUDES = -I$(top_srcdir)/libkdegames -I$(top_srcdir)/libkdegames/highscore $(all_includes)
+
+# Don't compile with hidden symbols since we are a library.
+if disable_VISIBILITY
+KDE_CXXFLAGS = -fvisibility=default
+endif
+
+noinst_LTLIBRARIES = libksirtetbase.la
+libksirtetbase_la_LDFLAGS = $(all_libraries)
+
+noinst_HEADERS = kzoommainwindow.h piece.h gtetris.h factory.h highscores.h \
+ board.h settings.h field.h inter.h main.h
+libksirtetbase_la_SOURCES = kzoommainwindow.cpp main.cpp field.cpp piece.cpp highscores.cpp \
+ factory.cpp gtetris.cpp board.cpp settings.cpp \
+ inter.cpp baseprefs.kcfgc
+METASOURCES = AUTO
diff --git a/libksirtet/base/README b/libksirtet/base/README
new file mode 100644
index 00000000..a16060b1
--- /dev/null
+++ b/libksirtet/base/README
@@ -0,0 +1 @@
+This directory contains code shared between ksirtet, kfouleggs and klickety.
diff --git a/libksirtet/base/baseprefs.kcfgc b/libksirtet/base/baseprefs.kcfgc
new file mode 100644
index 00000000..41c852af
--- /dev/null
+++ b/libksirtet/base/baseprefs.kcfgc
@@ -0,0 +1,7 @@
+# Code generation options for kconfig_compiler
+File=libksirtet1.kcfg
+#IncludeFiles=defines.h
+ClassName=BasePrefs
+Singleton=true
+#CustomAdditions=true
+Mutators=MenubarVisible,BlockSize
diff --git a/libksirtet/base/board.cpp b/libksirtet/base/board.cpp
new file mode 100644
index 00000000..257e72c3
--- /dev/null
+++ b/libksirtet/base/board.cpp
@@ -0,0 +1,429 @@
+#include "board.h"
+#include "board.moc"
+
+#include <knotifyclient.h>
+#include <klocale.h>
+#include <kzoommainwindow.h>
+
+#include "piece.h"
+#include "factory.h"
+#include "baseprefs.h"
+
+using namespace KGrid2D;
+
+//-----------------------------------------------------------------------------
+FixedCanvasView::FixedCanvasView(QWidget *parent, const char *name)
+ : QCanvasView(parent, name, WNoAutoErase)
+{}
+
+QSize FixedCanvasView::sizeHint() const
+{
+ if ( canvas()==0 ) return QSize();
+ return canvas()->size() + 2 * QSize(frameWidth(), frameWidth());
+}
+
+void FixedCanvasView::adjustSize()
+{
+ setFixedSize(sizeHint());
+}
+
+//-----------------------------------------------------------------------------
+const BaseBoard::DirectionData BaseBoard::DIRECTION_DATA[Nb_Direction] = {
+ { SquareBase::Left, Left },
+ { SquareBase::Right, Right },
+ { SquareBase::Down, Up },
+ { SquareBase::Up, Down }
+};
+
+BaseBoard::BaseBoard(bool graphic, QWidget *parent)
+: FixedCanvasView(parent, "board"),
+ GenericTetris(bfactory->bbi.width, bfactory->bbi.height,
+ bfactory->bbi.withPieces, graphic),
+ state(GameOver), timer(this), sequences(0), main(0), _next(0),
+ _arcade(false)
+{
+ if (graphic) {
+ setVScrollBarMode(AlwaysOff);
+ setHScrollBarMode(AlwaysOff);
+ setFrameStyle( QFrame::Panel | QFrame::Sunken );
+
+ sequences = new SequenceArray;
+ main = new BlockInfo(*sequences);
+ setCanvas(main);
+ if (bfactory->bbi.withPieces)
+ _next = new BlockInfo(*sequences);
+ setBlockInfo(main, _next);
+
+ connect(&timer, SIGNAL(timeout()), SLOT(timeout()));
+
+ Piece::info().loadColors();
+ KZoomMainWindow::addWidget(this);
+ }
+}
+
+void BaseBoard::copy(const GenericTetris &g)
+{
+ GenericTetris::copy(g);
+ state = static_cast<const BaseBoard &>(g).state;
+}
+
+void BaseBoard::settingsChanged()
+{
+ Q_ASSERT( graphic() );
+ Piece::info().loadColors();
+}
+
+void BaseBoard::adjustSize()
+{
+ int size = BasePrefs::blockSize();
+
+ sequences->setBlockSize(size);
+ main->resize(matrix().width() * size, matrix().height() * size);
+ for (uint i=0; i<matrix().width(); i++)
+ for (uint j=0; j<firstClearLine(); j++) {
+ Coord c(i, j);
+ if ( matrix()[c]==0 ) continue;
+ partialMoveBlock(c, QPoint(0, 0));
+ }
+
+ if (_next) {
+ Coord c = Piece::info().maxSize() + Coord(2, 2);
+ _next->resize(c.first * size, c.second * size);
+ _nextPiece->moveCenter();
+ }
+
+ FixedCanvasView::adjustSize();
+}
+
+BaseBoard::~BaseBoard()
+{
+ if ( graphic() ) {
+ setBlockInfo(0, 0); // destruct all sprites before deleting canvas
+ delete _next;
+ delete main;
+ delete sequences;
+ }
+}
+
+void BaseBoard::init(bool arcade)
+{
+ _arcade = arcade;
+ _arcadeStageDone = false;
+}
+
+void BaseBoard::start(const GTInitData &data)
+{
+ Q_ASSERT( graphic() );
+ if ( !_arcadeStageDone || _arcadeStage==bfactory->bbi.nbArcadeStages )
+ _arcadeStage = 0;
+ _arcadeStageDone = false;
+ state = Normal;
+ GenericTetris::start(data); // NB: the timer is started by updateLevel !
+ if (_arcade) arcadePrepare();
+}
+
+void BaseBoard::stop()
+{
+ timer.stop();
+ state = GameOver;
+}
+
+void BaseBoard::pause()
+{
+ Q_ASSERT( graphic() );
+ timer.stop();
+ _oldState = state;
+ state = Paused;
+ showBoard(false);
+}
+
+void BaseBoard::gameOver()
+{
+ stop();
+ emit gameOverSignal();
+}
+
+void BaseBoard::showCanvas(QCanvas *c, bool show)
+{
+ QCanvasItemList l = c->allItems();
+ QCanvasItemList::Iterator it;
+ for (it=l.begin(); it!=l.end(); ++it) {
+ if (show) (*it)->show();
+ else (*it)->hide();
+ }
+ c->update();
+}
+
+void BaseBoard::showBoard(bool show)
+{
+ showCanvas(main, show);
+}
+
+void BaseBoard::unpause()
+{
+ Q_ASSERT( graphic() );
+ showBoard(true);
+ state = _oldState;
+ startTimer();
+}
+
+void BaseBoard::updateRemoved(uint newRemoved)
+{
+ GenericTetris::updateRemoved(newRemoved);
+ emit removedUpdated();
+}
+
+void BaseBoard::updateScore(uint newScore)
+{
+ GenericTetris::updateScore(newScore);
+ emit scoreUpdated();
+}
+
+int BaseBoard::firstColumnBlock(uint col) const
+{
+ for (int j=firstClearLine()-1; j>=0; j--) {
+ Coord c(col, j);
+ if ( matrix()[c]!=0 ) return j;
+ }
+ return -1;
+}
+
+//-----------------------------------------------------------------------------
+void BaseBoard::_beforeRemove(bool first)
+{
+ if ( graphic() ) {
+ state = ( beforeRemove(first) ? BeforeRemove : Normal );
+ if ( state==BeforeRemove ) {
+ startTimer();
+ return;
+ }
+ }
+ remove();
+ _afterRemove(true);
+}
+
+void BaseBoard::remove()
+{
+ for (uint j=0; j<firstClearLine(); j++)
+ for (uint i=0; i<matrix().width(); i++) {
+ Coord c(i, j);
+ if ( matrix()[c]==0 || !toBeRemoved(c) ) continue;
+ removeBlock(c);
+ }
+ computeInfos();
+ if ( graphic() ) {
+ main->update();
+ KNotifyClient::event(winId(), "removed", i18n("Blocks removed"));
+ }
+}
+
+bool BaseBoard::doFall(bool doAll, bool first, bool lineByLine)
+{
+ Q_ASSERT( !lineByLine || !doAll );
+
+ if ( !doAll ) {
+ if (first) loop = 0;
+ else loop++;
+ }
+ bool final = (doAll || lineByLine
+ || loop==bfactory->bbi.nbFallStages);
+
+ for (uint i=0; i<matrix().width(); i++) {
+ // compute heights
+ // we must separate this computation since toFall() can depend
+ // directly on the disposition of blocks under the current one
+ // (for e.g. in kfouleggs)
+ // we do not rely on firstClearLine() here since this method is
+ // used in kfouleggs to make gift blocks fall down ...
+ uint h = 0;
+ QMemArray<uint> heights(matrix().height());
+ for (uint j=1; j<matrix().height(); j++) { // first line cannot fall
+ Coord src(i, j);
+ if ( toFall(src) ) h++;
+ heights[j] = h;
+ }
+
+ // do move
+ for (uint j=1; j<matrix().height(); j++) {
+ Coord src(i, j);
+ if( heights[j]==0 || matrix()[src]==0 ) continue;
+ if (lineByLine) final = false;
+ uint k = j - (lineByLine ? 1 : heights[j]);
+ Coord dest(i, k);
+ if ( final || lineByLine ) moveBlock(src, dest);
+ else partialBlockFall(src, dest);
+ }
+ }
+
+ if (final) computeInfos();
+ return final;
+}
+
+void BaseBoard::_afterRemove(bool first)
+{
+ AfterRemoveResult r = afterRemove(!graphic(), first);
+ switch (r) {
+ case Done:
+ state = Normal;
+ _afterAfterRemove();
+ return;
+ case NeedAfterRemove:
+ state = AfterRemove;
+ startTimer();
+ return;
+ case NeedRemoving:
+ _beforeRemove(true);
+ return;
+ }
+}
+
+BaseBoard::AfterRemoveResult BaseBoard::afterRemove(bool doAll, bool first)
+{
+ return (doFall(doAll, first, false) ? Done : NeedAfterRemove);
+}
+
+void BaseBoard::_afterAfterRemove()
+{
+ if ( isArcade() && arcadeDone()>=arcadeTodo() ) {
+ _arcadeStage++;
+ _arcadeStageDone = true;
+ gameOver();
+ return;
+ }
+ if ( !afterAfterRemove() ) gameOver();
+ else if ( graphic() ) startTimer();
+}
+
+bool BaseBoard::timeout()
+{
+ Q_ASSERT( graphic() );
+ if ( state==GameOver ) return true;
+ switch (state) {
+ case BeforeRemove: _beforeRemove(FALSE); break;
+ case AfterRemove: _afterRemove(FALSE); break;
+ default: return false;
+ }
+ main->update();
+ return true;
+}
+
+bool BaseBoard::startTimer()
+{
+ Q_ASSERT( graphic() );
+ if ( state==GameOver ) return true;
+ switch (state) {
+ case BeforeRemove:
+ timer.start(bfactory->bbi.beforeRemoveTime, true);
+ break;
+ case AfterRemove:
+ timer.start(bfactory->bbi.afterRemoveTime, true);
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+bool BaseBoard::beforeRemove(bool first)
+{
+ if (first) loop = 0;
+ else loop++;
+
+ for (uint j=0; j<firstClearLine(); j++)
+ for (uint i=0; i<matrix().width(); i++) {
+ Coord c(i, j);
+ if ( toBeRemoved(c) ) matrix()[c]->toggleLight();
+ }
+
+ return ( loop!=bfactory->bbi.nbToggles );
+}
+
+
+//-----------------------------------------------------------------------------
+void BaseBoard::partialBlockFall(const Coord &src, const Coord &dest)
+{
+ Q_ASSERT( loop<bfactory->bbi.nbFallStages );
+
+ float c = float(loop+1) / bfactory->bbi.nbFallStages * BasePrefs::blockSize();
+ int xdec = dest.first - src.first;
+ int ydec = src.second - dest.second;
+ QPoint p(int(xdec * c), int(ydec * c));
+ partialMoveBlock(src, p);
+}
+
+uint BaseBoard::findGroup(Square<int> &field, const Coord &c) const
+{
+ uint nb = 0;
+ _findGroup(field, c, nb, false);
+ return nb;
+}
+
+void BaseBoard::setGroup(Square<int> &field, const Coord &c, uint nb) const
+{
+ _findGroup(field, c, nb, true);
+}
+
+void BaseBoard::_findGroup(Square<int> &field, const Coord &c,
+ uint &nb, bool set) const
+{
+ if (!set) nb++;
+ field[c] = (set ? (int)nb : -1);
+ uint value = matrix()[c]->value();
+ CoordList n = matrix().neighbours(c, true, true);
+ for (CoordList::const_iterator i = n.begin(); i!=n.end(); ++i)
+ blockInGroup(field, *i, value, nb, set);
+}
+
+void BaseBoard::blockInGroup(Square<int> &field, const Coord &c, uint value,
+ uint &nb, bool set) const
+{
+ if ( matrix()[c]==0 ) return;
+ if ( matrix()[c]->value()!=value ) return;
+ if ( field[c]!=(set ? -1 : 0) ) return;
+ _findGroup(field, c, nb, set);
+}
+
+QMemArray<uint> BaseBoard::findGroups(Square<int> &field, uint minSize,
+ bool exitAtFirstFound) const
+{
+ field.fill(0);
+ QMemArray<uint> groups;
+ for (uint j=0; j<firstClearLine(); j++)
+ for (uint i=0; i<matrix().width(); i++) {
+ Coord c(i, j);
+ if ( matrix()[c]==0 || matrix()[c]->isGarbage() ) continue;
+ if ( field[c]!=0 ) continue;
+ uint nb = findGroup(field, c);
+ setGroup(field, c, nb);
+ if ( nb>=minSize ) {
+ uint s = groups.size();
+ groups.resize(s+1);
+ groups[s] = nb;
+ if (exitAtFirstFound) return groups;
+ }
+ }
+ return groups;
+}
+
+uint BaseBoard::drawCode(const Coord &c) const
+{
+ uint v = matrix()[c]->value();
+ uint code = 0;
+ for (uint i=0; i<Nb_Direction; i++) {
+ Coord nc = SquareBase::neighbour(c, DIRECTION_DATA[i].neighbour);
+ if ( !matrix().inside(nc) || matrix()[nc]==0
+ || matrix()[nc]->value()!=v ) continue;
+ code |= DIRECTION_DATA[i].direction;
+ }
+ return code;
+}
+
+void BaseBoard::computeNeighbours()
+{
+ for (uint j=0; j<firstClearLine(); j++)
+ for (uint i=0; i<matrix().width(); i++) {
+ Coord c(i, j);
+ if ( matrix()[c]==0 || matrix()[c]->isGarbage() ) continue;
+ matrix()[c]->sprite()->setFrame( drawCode(c) );
+ }
+}
diff --git a/libksirtet/base/board.h b/libksirtet/base/board.h
new file mode 100644
index 00000000..443c6532
--- /dev/null
+++ b/libksirtet/base/board.h
@@ -0,0 +1,134 @@
+#ifndef BASE_BOARD_H
+#define BASE_BOARD_H
+
+#include <qtimer.h>
+#include <qcanvas.h>
+
+#include "gtetris.h"
+
+#include <kdemacros.h>
+
+class SequenceArray;
+class BlockInfo;
+
+//-----------------------------------------------------------------------------
+class KDE_EXPORT FixedCanvasView : public QCanvasView
+{
+ Q_OBJECT
+public:
+ FixedCanvasView(QWidget *parent = 0, const char *name = 0);
+
+ virtual QSize sizeHint() const;
+
+public slots:
+ virtual void adjustSize();
+};
+
+//-----------------------------------------------------------------------------
+class KDE_EXPORT BaseBoard : public FixedCanvasView, public GenericTetris
+{
+ Q_OBJECT
+ public:
+ enum Direction { Left = 1, Right = 2, Up = 4, Down = 8, Nb_Direction = 4 };
+ private:
+ struct DirectionData {
+ KGrid2D::SquareBase::Neighbour neighbour;
+ Direction direction;
+ };
+ static const DirectionData DIRECTION_DATA[Nb_Direction];
+
+ public:
+ BaseBoard(bool graphic, QWidget *parent);
+ virtual ~BaseBoard();
+ void copy(const GenericTetris &);
+
+ void init(bool arcade);
+ virtual void start(const GTInitData &);
+ virtual void pause();
+ virtual void unpause();
+ virtual void stop();
+ bool isGameOver() const { return state==GameOver; }
+ bool isPaused() const { return state==Paused; }
+
+ bool isArcade() const { return _arcade; }
+ uint arcadeStage() const { return _arcadeStage; }
+ bool arcadeStageDone() const { return _arcadeStageDone; }
+ virtual uint arcadeTodo() const { return 0; }
+ virtual uint arcadeDone() const { return 0; }
+
+ virtual void settingsChanged();
+ BlockInfo *next() const { return _next; }
+
+ int firstColumnBlock(uint column) const;
+
+ public slots:
+ virtual void adjustSize();
+
+ protected slots:
+ virtual bool timeout(); // return true if treated
+
+ signals:
+ void updatePieceConfigSignal();
+ void removedUpdated();
+ void scoreUpdated();
+ void gameOverSignal();
+
+ protected:
+ virtual bool beforeRemove(bool first);
+ void _beforeRemove(bool first);
+ enum AfterRemoveResult { Done, NeedAfterRemove, NeedRemoving };
+ virtual AfterRemoveResult afterRemove(bool doAll, bool first);
+ void _afterAfterRemove();
+ virtual bool afterAfterRemove() = 0;
+ virtual bool startTimer(); // return true if treated
+ virtual bool toBeRemoved(const KGrid2D::Coord &) const = 0;
+ virtual void remove();
+ virtual bool toFall(const KGrid2D::Coord &) const = 0;//height>0 when called
+ virtual bool doFall(bool doAll, bool first, bool lineByLine);
+ virtual void gameOver();
+ virtual void arcadePrepare() {}
+
+ uint drawCode(const KGrid2D::Coord &) const;
+ void computeNeighbours();
+ void partialBlockFall(const KGrid2D::Coord &src, const KGrid2D::Coord &dest);
+
+ // return the sizes of the groups (>=minSize)
+ QMemArray<uint> findGroups(KGrid2D::Square<int> &field, uint minSize,
+ bool exitAtFirstFound = false) const;
+ // find group size and put -1 in the corresponding blocks (these blocks
+ // should be 0 at start)
+ uint findGroup(KGrid2D::Square<int> &field, const KGrid2D::Coord &) const;
+ // set the size of the group in the blocks (these blocks should be -1
+ // at start ie you should have called findGroup() before)
+ void setGroup(KGrid2D::Square<int> &field, const KGrid2D::Coord &c,
+ uint nb) const;
+
+ void updateRemoved(uint newRemoved);
+ void updateScore(uint newScore);
+
+ virtual void showBoard(bool show);
+ void showCanvas(QCanvas *c, bool show);
+
+ enum BoardState { GameOver, Normal, Paused,
+ DropDown, BeforeGlue, AfterGlue, BeforeRemove,
+ AfterRemove, AfterGift };
+ BoardState state, _oldState;
+ QTimer timer;
+ SequenceArray *sequences;
+ BlockInfo *main, *_next;
+ uint loop;
+
+ private:
+ bool _arcade, _arcadeStageDone;
+ uint _arcadeStage;
+
+ void _afterRemove(bool first);
+ void updatePieceConfig() { emit updatePieceConfigSignal(); }
+
+ void _findGroup(KGrid2D::Square<int> &field, const KGrid2D::Coord &c,
+ uint &nb, bool set) const;
+ void blockInGroup(KGrid2D::Square<int> &field, const KGrid2D::Coord &c,
+ uint value, uint &nb, bool ser) const;
+};
+
+#endif
diff --git a/libksirtet/base/factory.cpp b/libksirtet/base/factory.cpp
new file mode 100644
index 00000000..55850f0b
--- /dev/null
+++ b/libksirtet/base/factory.cpp
@@ -0,0 +1,52 @@
+#include "factory.h"
+
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <kglobal.h>
+#include <klocale.h>
+
+#include "settings.h"
+
+
+BaseFactory *BaseFactory::_self = 0;
+
+BaseFactory::BaseFactory(const MainData &md, const BaseBoardInfo &bi)
+ : mainData(md), bbi(bi)
+{
+ Q_ASSERT( _self==0 );
+ _self = this;
+ _aboutData =
+ new KAboutData(md.appName, md.trName, md.longVersion, md.description,
+ KAboutData::License_GPL,
+ "(c) 1995, Eirik Eng\n(c) 1996-2004, Nicolas Hadacek",
+ 0, md.homepage);
+ _aboutData->addAuthor("Nicolas Hadacek", 0, "hadacek@kde.org");
+ _aboutData->addCredit("Eirik Eng", I18N_NOOP("Core engine"));
+}
+
+void BaseFactory::init(int argc, char **argv)
+{
+ KCmdLineArgs::init(argc, argv, _aboutData);
+ (void)new KApplication;
+ KGlobal::locale()->insertCatalogue("libkdegames");
+ KGlobal::locale()->insertCatalogue("libksirtet");
+}
+
+BaseFactory::~BaseFactory()
+{
+ delete kapp;
+ delete _aboutData;
+ Q_ASSERT(_self);
+ _self = 0;
+}
+
+QWidget *BaseFactory::createAppearanceConfig()
+{
+ return new BaseAppearanceConfig;
+}
+
+QWidget *BaseFactory::createColorConfig()
+{
+ return new ColorConfig;
+}
diff --git a/libksirtet/base/factory.h b/libksirtet/base/factory.h
new file mode 100644
index 00000000..b542205e
--- /dev/null
+++ b/libksirtet/base/factory.h
@@ -0,0 +1,60 @@
+#ifndef BASE_FACTORY_H
+#define BASE_FACTORY_H
+
+#include <qglobal.h>
+
+#include <kdemacros.h>
+
+struct MainData {
+ const char *appName, *trName, *description, *homepage, *removedLabel,
+ *version, *longVersion;
+};
+
+struct BaseBoardInfo {
+ uint width, height;
+ bool withPieces;
+
+ uint beforeRemoveTime, afterRemoveTime;
+ uint nbToggles, nbFallStages;
+
+ uint nbArcadeStages;
+
+ const uint *histogram;
+ uint histogramSize;
+ bool scoreBound;
+};
+
+class BaseBoard;
+class BaseInterface;
+class QWidget;
+class KAboutData;
+
+#define bfactory BaseFactory::self()
+
+class KDE_EXPORT BaseFactory
+{
+ public:
+ BaseFactory(const MainData &, const BaseBoardInfo &);
+ virtual ~BaseFactory();
+ void init(int argc, char **argv);
+
+ static BaseFactory *self() { return _self; }
+
+ const MainData &mainData;
+ const BaseBoardInfo &bbi;
+
+ virtual BaseBoard *createBoard(bool graphic, QWidget *parent) = 0;
+ virtual BaseInterface *createInterface(QWidget *parent) = 0;
+
+ virtual QWidget *createAppearanceConfig();
+ virtual QWidget *createColorConfig();
+ virtual QWidget *createGameConfig() { return 0; }
+
+ protected:
+ KAboutData *_aboutData;
+
+ private:
+ static BaseFactory *_self;
+};
+
+#endif
diff --git a/libksirtet/base/field.cpp b/libksirtet/base/field.cpp
new file mode 100644
index 00000000..53f6220a
--- /dev/null
+++ b/libksirtet/base/field.cpp
@@ -0,0 +1,162 @@
+#include "field.h"
+
+#include <qwhatsthis.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+
+#include <klocale.h>
+#include <kcanvasrootpixmap.h>
+#include <knotifyclient.h>
+#include <kgamelcd.h>
+
+#include "factory.h"
+#include "board.h"
+#include "baseprefs.h"
+
+
+const char *BaseField::BUTTON_TEXTS[NB_BUTTON_TYPE] = {
+ I18N_NOOP("Start"), I18N_NOOP("Resume"), I18N_NOOP("Proceed")
+};
+
+BaseField::BaseField(QWidget *w)
+ : _widget(w), _boardLayout(0), _label(0), _button(0)
+{
+ top = new QGridLayout(w, 3, 5, 10);
+
+ lcds = new QGridLayout(7, 1, 5);
+ top->addLayout(lcds, 1, 0);
+ lcds->setRowStretch(1, 0);
+
+ board = bfactory->createBoard(true, w);
+ _boardRootPixmap = new KCanvasRootPixmap(board);
+ _boardRootPixmap->start();
+ top->addWidget(board, 1, 2);
+}
+
+void BaseField::init(bool AI, bool multiplayer, bool server, bool first,
+ const QString &name)
+{
+ _flags.AI = AI;
+ _flags.multiplayer = multiplayer;
+ _flags.server = server;
+ _flags.first = first;
+ QString text = (AI ? i18n("%1\n(AI player)").arg(name)
+ : (multiplayer ? i18n("%1\n(Human player)").arg(name)
+ : QString::null));
+ if ( first && !server ) text += i18n("\nWaiting for server");
+ setMessage(text, (first && server ? StartButton : NoButton));
+ showScore->resetColor();
+ board->init(false);
+}
+
+void BaseField::setArcade()
+{
+ board->init(true);
+ setMessage(i18n("Stage #1"), StartButton);
+}
+
+bool BaseField::isArcade() const
+{
+ return board->isArcade();
+}
+
+void BaseField::setMessage(const QString &label, ButtonType type)
+{
+ delete _label;
+ _label = 0;
+ delete _button;
+ _button = 0;
+ delete _boardLayout;
+ _boardLayout = 0;
+
+ if ( label.isEmpty() && type==NoButton ) {
+ _widget->setFocus();
+ return;
+ }
+
+ _boardLayout = new QVBoxLayout(board);
+ _boardLayout->addStretch(3);
+ if ( !label.isEmpty() ) {
+ QString str = (isArcade() ? i18n("Arcade game") + '\n'
+ : QString::null) + label;
+ _label = new QLabel(str, board);
+ _label->setAlignment(Qt::AlignCenter);
+ _label->setFrameStyle( QFrame::Panel | QFrame::Sunken );
+ _boardLayout->addWidget(_label, 0, Qt::AlignCenter);
+ _label->show();
+ }
+ _boardLayout->addStretch(1);
+ if ( type!=NoButton ) {
+ _button = new QPushButton(i18n(BUTTON_TEXTS[type]), board);
+ _button->setFocus();
+ const char *slot = (type==ResumeButton ? SLOT(pause())
+ : SLOT(start()));
+ _button->connect(_button, SIGNAL(clicked()),
+ _widget->parent(), slot);
+ _boardLayout->addWidget(_button, 0, Qt::AlignCenter);
+ _button->show();
+ }
+ _boardLayout->addStretch(3);
+}
+
+void BaseField::start(const GTInitData &data)
+{
+ _firstScore = KExtHighscore::firstScore();
+ _lastScore = KExtHighscore::lastScore();
+ hideMessage();
+ board->start(data);
+}
+
+void BaseField::pause(bool pause)
+{
+ if (pause) {
+ board->pause();
+ setMessage(i18n("Game paused"), ResumeButton);
+ } else {
+ board->unpause();
+ hideMessage();
+ }
+}
+
+void BaseField::stop(bool gameover)
+{
+ board->stop();
+ ButtonType button = StartButton;
+ QString msg = (gameover ? i18n("Game over") : QString::null);
+ if ( board->isArcade() && board->arcadeStageDone() ) {
+ if ( board->arcadeStage()==bfactory->bbi.nbArcadeStages )
+ msg = i18n("The End");
+ else {
+ msg = i18n("Stage #%1 done").arg(board->arcadeStage());
+ button = ProceedButton;
+ }
+ }
+ setMessage(msg, button);
+}
+
+void BaseField::gameOver(const KExtHighscore::Score &score, QWidget *parent)
+{
+ KNotifyClient::event(parent->winId(), "game over", i18n("Game Over"));
+ KExtHighscore::submitScore(score, parent);
+}
+
+void BaseField::scoreUpdated()
+{
+ showScore->display( (int)board->score() );
+ if (_flags.multiplayer) return;
+
+ QColor color;
+ if ( _firstScore<currentScore() ) color = Qt::red;
+ else if ( _lastScore<currentScore() ) color = Qt::blue;
+ showScore->setColor(color);
+}
+
+void BaseField::settingsChanged()
+{
+ QColor color = BasePrefs::fadeColor();
+ double s = BasePrefs::fadeIntensity();
+ _boardRootPixmap->setFadeEffect(s, color);
+ board->canvas()->setBackgroundColor(color);
+ board->settingsChanged();
+}
diff --git a/libksirtet/base/field.h b/libksirtet/base/field.h
new file mode 100644
index 00000000..d006a052
--- /dev/null
+++ b/libksirtet/base/field.h
@@ -0,0 +1,66 @@
+#ifndef BASE_FIELD_H
+#define BASE_FIELD_H
+
+#include <kexthighscore.h>
+
+#include <kdemacros.h>
+
+class QVBoxLayout;
+class QGridLayout;
+class KGameLCD;
+class KGameLCDList;
+class BaseBoard;
+class QLabel;
+class QButton;
+class GTInitData;
+class KCanvasRootPixmap;
+
+class KDE_EXPORT BaseField
+{
+ public:
+ BaseField(QWidget *widget);
+ virtual ~BaseField() {}
+
+ virtual KExtHighscore::Score currentScore() const = 0;
+ static void gameOver(const KExtHighscore::Score &, QWidget *parent);
+
+ virtual void setArcade();
+ bool isArcade() const;
+
+ protected:
+ QGridLayout *top, *lcds;
+ KGameLCD *showScore;
+ KGameLCDList *removedList, *scoreList;
+ BaseBoard *board;
+
+ virtual void scoreUpdated();
+ virtual void init(bool AI, bool multiplayer, bool server, bool first,
+ const QString &name);
+ virtual void start(const GTInitData &);
+ virtual void pause(bool pause);
+ virtual void stop(bool gameover);
+ virtual void settingsChanged();
+
+ private:
+ QWidget *_widget;
+ struct Flags {
+ bool AI, multiplayer, server, first;
+ };
+ Flags _flags;
+ uint _arcadeStage;
+ QVBoxLayout *_boardLayout;
+ QLabel *_label;
+ QButton *_button;
+ KCanvasRootPixmap *_boardRootPixmap;
+ KExtHighscore::Score _firstScore, _lastScore;
+
+ enum ButtonType { StartButton = 0, ResumeButton, ProceedButton,
+ NB_BUTTON_TYPE, NoButton = NB_BUTTON_TYPE };
+ static const char *BUTTON_TEXTS[NB_BUTTON_TYPE];
+
+ bool hasButton() const { return _flags.server && _flags.first; }
+ void setMessage(const QString &label, ButtonType);
+ void hideMessage() { setMessage(QString::null, NB_BUTTON_TYPE); }
+};
+
+#endif
diff --git a/libksirtet/base/gtetris.cpp b/libksirtet/base/gtetris.cpp
new file mode 100644
index 00000000..2141f9ef
--- /dev/null
+++ b/libksirtet/base/gtetris.cpp
@@ -0,0 +1,241 @@
+#include "gtetris.h"
+
+#include "piece.h"
+
+
+using namespace KGrid2D;
+
+GenericTetris::GenericTetris(uint width, uint height, bool withPieces,
+ bool graphic)
+ : _nextPiece(0), _currentPiece(0), _score(0), _nbRemoved(0),
+ _nbClearLines(height), _main(0),
+ _graphic(graphic), _matrix(width, height)
+{
+ if (withPieces) {
+ _nextPiece = new Piece;
+ _currentPiece = new Piece;
+ }
+ _matrix.fill(0);
+}
+
+void GenericTetris::copy(const GenericTetris &g)
+{
+ Q_ASSERT(_currentPiece);
+ // copy to non graphic
+ _score = g._score;
+ _level = g._level;
+ _nbRemoved = g._nbRemoved;
+ _nbClearLines = g._nbClearLines;
+ _currentPos = g._currentPos;
+ _nextPiece->copy(g._nextPiece);
+ _currentPiece->copy(g._currentPiece);
+ for (uint i=0; i<_matrix.size(); i++) {
+ Coord c = _matrix.coord(i);
+ delete _matrix[c];
+ if ( g._matrix[c] ) _matrix[c] = new Block(g._matrix[c]->value());
+ else _matrix[c] = 0;
+ }
+}
+
+void GenericTetris::clear()
+{
+ _currentPos = Coord(0, -1);
+ for (uint i=0; i<_matrix.size(); i++) removeBlock(_matrix.coord(i));
+ computeInfos();
+}
+
+GenericTetris::~GenericTetris()
+{
+ // everything should already be done by setBlockInfo(0, 0);
+}
+
+void GenericTetris::setBlockInfo(BlockInfo *main, BlockInfo *next)
+{
+ Q_ASSERT( _graphic );
+ if (main) {
+ _main = main;
+ if (_currentPiece) {
+ Q_ASSERT(next);
+ _nextPiece->setBlockInfo(next);
+ _currentPiece->setBlockInfo(main);
+ }
+ } else { // before destruction
+ clear();
+ delete _currentPiece;
+ delete _nextPiece;
+ }
+}
+
+void GenericTetris::start(const GTInitData &data)
+{
+ Q_ASSERT( _graphic );
+ _random.setSeed(data.seed);
+ _initLevel = data.initLevel;
+ updateScore(0);
+ updateLevel(_initLevel);
+ updateRemoved(0);
+ clear();
+ if (_nextPiece) {
+ _nextPiece->setRandomSequence(&_random);
+ _nextPiece->generateNext();
+ newPiece();
+ }
+}
+
+void GenericTetris::dropDown()
+{
+ uint dropHeight = moveTo(Coord(0, -_currentPos.second));
+ pieceDropped(dropHeight);
+}
+
+void GenericTetris::oneLineDown()
+{
+ if ( moveTo(Coord(0, -1))==0 ) pieceDropped(0);
+}
+
+bool GenericTetris::newPiece()
+{
+ Q_ASSERT(_currentPiece);
+ Coord min = _nextPiece->min();
+ _currentPos.second = _matrix.height() - 1 + min.second;
+ _currentPos.first = (_matrix.width() - _nextPiece->size().first)/2
+ - min.first;
+ if ( !canPosition(_currentPos, _nextPiece)) {
+ _currentPos.second = -1;
+ return false;
+ }
+ _currentPiece->copy(_nextPiece);
+ if (_graphic) {
+ _currentPiece->move(toPoint(_currentPos));
+ _currentPiece->show(true);
+ updatePieceConfig();
+ }
+ _nextPiece->generateNext();
+ if (_graphic) {
+ _nextPiece->moveCenter();
+ _nextPiece->show(true);
+ updateNextPiece();
+ }
+ return true;
+}
+
+bool GenericTetris::canPosition(const Coord &pos, const Piece *piece) const
+{
+ for(uint k=0; k<piece->nbBlocks(); k++) {
+ Coord c(piece->pos(k, pos));
+ if ( !_matrix.inside(c) || _matrix[c]!=0 )
+ return false; // outside or something in the way
+ }
+ return true;
+}
+
+uint GenericTetris::moveTo(const Coord &dec)
+{
+ Q_ASSERT(_currentPiece);
+ Q_ASSERT(dec.first==0 || dec.second==0);
+
+ Coord newPos = _currentPos;
+ Coord d(0, 0);
+ uint n, i;
+
+ if (dec.first) {
+ d.first = (dec.first<0 ? -1 : 1);
+ n = kAbs(dec.first);
+ } else {
+ d.second = (dec.second<0 ? -1 : 1);
+ n = kAbs(dec.second);
+ }
+
+ for (i=0; i<n; i++) {
+ if ( !canPosition(newPos + d, _currentPiece) ) break;
+ newPos = newPos + d;
+ }
+ if ( i!=0 ) { // piece can be moved
+ _currentPos = newPos;
+ if (_graphic) {
+ _currentPiece->move(toPoint(newPos));
+ updatePieceConfig();
+ }
+ }
+ return i;
+}
+
+bool GenericTetris::rotate(bool left)
+{
+ Q_ASSERT(_currentPiece);
+
+ Piece tmp;
+ tmp.copy(_currentPiece);
+ QPoint p(0, 0);
+ tmp.rotate(left, p);
+ if ( canPosition(_currentPos, &tmp) ) {
+ if (_graphic) p = toPoint(_currentPos);
+ _currentPiece->rotate(left, p);
+ if (_graphic) updatePieceConfig();
+ return true;
+ }
+ return false;
+}
+
+void GenericTetris::computeInfos()
+{
+ _nbClearLines = 0;
+ for (uint j=_matrix.height(); j>0; j--) {
+ for (uint i=0; i<_matrix.width(); i++)
+ if ( _matrix[Coord(i, j-1)]!=0 ) return;
+ _nbClearLines++;
+ }
+}
+
+void GenericTetris::setBlock(const Coord &c, Block *b)
+{
+ Q_ASSERT( b && _matrix[c]==0 );
+ _matrix[c] = b;
+ if (_graphic) {
+ QPoint p = toPoint(c);
+ b->sprite()->move(p.x(), p.y());
+ }
+}
+
+void GenericTetris::removeBlock(const Coord &c)
+{
+ delete _matrix[c];
+ _matrix[c] = 0;
+}
+
+void GenericTetris::moveBlock(const Coord &src, const Coord &dest)
+{
+ Q_ASSERT( _matrix[dest]==0 );
+ if ( _matrix[src] ) {
+ setBlock(dest, _matrix[src]);
+ _matrix[src] = 0;
+ }
+}
+
+QPoint GenericTetris::toPoint(const Coord &c) const
+{
+ return _main->toPoint(Coord(c.first, _matrix.height() - 1 - c.second));
+}
+
+void GenericTetris::gluePiece()
+{
+ Q_ASSERT(_currentPiece);
+
+ for(uint k=0; k<_currentPiece->nbBlocks(); k++)
+ setBlock(_currentPiece->pos(k, _currentPos),
+ _currentPiece->takeBlock(k));
+ computeInfos();
+}
+
+void GenericTetris::bumpCurrentPiece(int dec)
+{
+ Q_ASSERT( _graphic && _currentPiece );
+ _currentPiece->move(toPoint(_currentPos) + QPoint(0, dec));
+}
+
+void GenericTetris::partialMoveBlock(const Coord &c, const QPoint &dec)
+{
+ Q_ASSERT( _graphic && _matrix[c]!=0 );
+ QPoint p = toPoint(c) + dec;
+ _matrix[c]->sprite()->move(p.x(), p.y());
+}
diff --git a/libksirtet/base/gtetris.h b/libksirtet/base/gtetris.h
new file mode 100644
index 00000000..48aefb9d
--- /dev/null
+++ b/libksirtet/base/gtetris.h
@@ -0,0 +1,178 @@
+/****************************************************************************
+**
+** Definition of GenericTetris, a generic class for implementing Tetris.
+**
+** Author : Eirik Eng
+** Created : 940126
+** Modified by Nicolas Hadacek
+**
+** Copyright (C) 1994 by Eirik Eng. All rights reserved.
+**
+**---------------------------------------------------------------------------
+**
+** The GenericTetris class is an abstract class that can be used to implement
+** the well known game of Tetris. It is totally independent of any hardware
+** platform or user interface mechanism. It has no notion of time, so you
+** have to supply the timer ticks (or heartbeat) of the game. Apart from
+** that this is a complete Tetris implementation.
+**
+** In the following it is assumed that the reader is familiar with the game
+** of Tetris.
+**
+** The class operates on a grid of squares (referred to as the "board" below),
+** where each of the different types of pieces in Tetris covers 4 squares. The
+** width and height of the board can be specified in the constructor (default
+** is 10x22). The coordinate (0,0) is at the TOP LEFT corner. The class
+** assumes that it has total control over the board and uses this to optimize
+** drawing of the board. If you need to update parts of the board
+** (e.g. if you are using a window system), use the updateBoard() function.
+**
+** An implementation of the game must subclass from TetrisBoard and must
+** implement these abstract functions:
+**
+** virtual void drawSquare(int x,int y,int value)
+**
+** This function is called when a square needs to be drawn
+** on the Tetris board. A value of 0 means that the square
+** should be erased. Values of 1 to 7 indicate the different
+** types of pieces. (Thus a minimal implementation can
+** draw 0 in one way and 1-7 in a second way). The x and y
+** values are coordinates on the Tetris board (see above).
+**
+** virtual void gameOver()
+**
+** This function is called when it is impossible to put a new
+** piece at the top of the board.
+**
+** To get a working minimal implementation of Tetris the following functions
+** must be called from the user interface:
+**
+** void startGame()
+**
+** Clears the board and starts a new game.
+**
+** void moveLeft()
+** void moveRight()
+** void rotateLeft()
+** void rotateRight()
+**
+** The standard Tetris controls for moving and rotating the
+** falling pieces.
+**
+** void dropDown();
+**
+** Another Tetris control, drops the falling piece and calls the
+** virtual function pieceDropped(), whose default implementation is
+** to create a new block which appears at the top of the board.
+**
+** void oneLineDown();
+**
+** This is where you supply the timer ticks, or heartbeat, of the
+** game. This function moves the current falling piece one line down
+** on the board, or, if that cannot be done, calls the virtual
+** function pieceDropped() (see dropDown() above). The time between
+** each call to this function directly affects the difficulty of the
+** game. If you want to pause the game, simply block calls to the
+** user control functions above and stop calling this function (you
+** might want to call hideBoard() also).
+**
+** And that's it! There are several other public functions you can call
+** and virtual functions you can overload to modify or extend the game.
+**
+** Do whatever you want with this code (i.e. the files gtetris.h,
+** gtetris.cpp, tpiece.h and tpiece.cpp). It is basically a weekend hack
+** and it would bring joy to my heart if anyone in any way would find
+** it useful.
+**
+** Nostalgia, comments and/or praise can be sent to: Eirik.Eng@troll.no
+**
+****************************************************************************/
+
+#ifndef GTETRIS_H
+#define GTETRIS_H
+
+#include <qpoint.h>
+
+#include <krandomsequence.h>
+#include <kgrid2d.h>
+
+#include <kdemacros.h>
+
+class Piece;
+class BlockInfo;
+class Block;
+
+struct GTInitData {
+ int seed;
+ uint initLevel;
+};
+
+class KDE_EXPORT GenericTetris
+{
+ public:
+ GenericTetris(uint width, uint height, bool withPieces, bool graphic);
+ virtual ~GenericTetris();
+ virtual void copy(const GenericTetris &);
+
+ void setBlockInfo(BlockInfo *main, BlockInfo *next);
+ virtual void start(const GTInitData &);
+
+ uint moveLeft(int steps = 1) { return moveTo(KGrid2D::Coord(-steps, 0)); }
+ uint moveRight(int steps = 1) { return moveTo(KGrid2D::Coord(steps, 0)); }
+ bool rotateLeft() { return rotate(true); }
+ bool rotateRight() { return rotate(false); }
+ virtual void oneLineDown();
+ virtual void dropDown();
+
+ KRandomSequence &randomSequence() { return _random; }
+ uint score() const { return _score; }
+ uint level() const { return _level; }
+ uint nbClearLines() const { return _nbClearLines; }
+ uint nbRemoved() const { return _nbRemoved; }
+ bool graphic() const { return _graphic; }
+ uint firstClearLine() const { return _matrix.height() - _nbClearLines; }
+ const KGrid2D::Coord &currentPos() const { return _currentPos; }
+ const Piece *nextPiece() const { return _nextPiece; }
+ const Piece *currentPiece() const { return _currentPiece; }
+ const KGrid2D::Square<Block *> &matrix() const { return _matrix; }
+
+ protected:
+ Piece *_nextPiece, *_currentPiece;
+
+ virtual void pieceDropped(uint /*dropHeight*/) {}
+ virtual bool newPiece(); // return false if cannot place new piece
+ virtual void gluePiece();
+ virtual void computeInfos();
+
+ virtual void updateRemoved(uint newNbRemoved) { _nbRemoved = newNbRemoved;}
+ virtual void updateScore(uint newScore) { _score = newScore; }
+ virtual void updateLevel(uint newLevel) { _level = newLevel; }
+
+ void setBlock(const KGrid2D::Coord &, Block *);
+ virtual void removeBlock(const KGrid2D::Coord &);
+ void moveBlock(const KGrid2D::Coord &src, const KGrid2D::Coord &dest);
+
+ virtual void updateNextPiece() {}
+ virtual void updatePieceConfig() {}
+ void bumpCurrentPiece(int dec);
+ void partialMoveBlock(const KGrid2D::Coord &, const QPoint &dec);
+
+ private:
+ QPoint toPoint(const KGrid2D::Coord &) const;
+ uint moveTo(const KGrid2D::Coord &dec);
+ bool rotate(bool left);
+ void clear();
+ bool canPosition(const KGrid2D::Coord &newPos, const Piece *newPiece) const;
+
+ GenericTetris(const GenericTetris &); // disabled
+
+ uint _score, _level, _nbRemoved;
+ uint _nbClearLines, _initLevel;
+ KGrid2D::Coord _currentPos;
+ BlockInfo *_main;
+ bool _graphic;
+ KGrid2D::Square<Block *> _matrix;
+ KRandomSequence _random;
+};
+
+#endif
diff --git a/libksirtet/base/highscores.cpp b/libksirtet/base/highscores.cpp
new file mode 100644
index 00000000..2b3596d7
--- /dev/null
+++ b/libksirtet/base/highscores.cpp
@@ -0,0 +1,19 @@
+#include "highscores.h"
+
+#include <kurl.h>
+
+#include "factory.h"
+
+
+using namespace KExtHighscore;
+
+BaseHighscores::BaseHighscores()
+{
+ setWWHighscores(KURL( bfactory->mainData.homepage ), bfactory->mainData.version);
+ const BaseBoardInfo &bi = bfactory->bbi;
+ if ( bi.histogramSize!=0 ) {
+ QMemArray<uint> a;
+ a.duplicate(bi.histogram, bi.histogramSize);
+ setScoreHistogram(a, bi.scoreBound ? ScoreBound : ScoreNotBound);
+ }
+}
diff --git a/libksirtet/base/highscores.h b/libksirtet/base/highscores.h
new file mode 100644
index 00000000..b3e7b99e
--- /dev/null
+++ b/libksirtet/base/highscores.h
@@ -0,0 +1,13 @@
+#ifndef BASE_HIGHSCORES_H
+#define BASE_HIGHSCORES_H
+
+#include <kexthighscore.h>
+#include <kdemacros.h>
+
+class KDE_EXPORT BaseHighscores : public KExtHighscore::Manager
+{
+ public:
+ BaseHighscores();
+};
+
+#endif
diff --git a/libksirtet/base/inter.cpp b/libksirtet/base/inter.cpp
new file mode 100644
index 00000000..4f40b63f
--- /dev/null
+++ b/libksirtet/base/inter.cpp
@@ -0,0 +1,15 @@
+#include "inter.h"
+
+#include <kexthighscore.h>
+
+
+void BaseInterface::showHighscores(QWidget *parent)
+{
+ if ( !_isPaused() ) _pause();
+ _showHighscores(parent);
+}
+
+void BaseInterface::_showHighscores(QWidget *parent)
+{
+ KExtHighscore::show(parent);
+}
diff --git a/libksirtet/base/inter.h b/libksirtet/base/inter.h
new file mode 100644
index 00000000..446a77d3
--- /dev/null
+++ b/libksirtet/base/inter.h
@@ -0,0 +1,23 @@
+#ifndef BASE_INTER_H
+#define BASE_INTER_H
+
+class QWidget;
+
+
+class BaseInterface
+{
+public:
+ BaseInterface() {}
+ virtual ~BaseInterface() {}
+
+ virtual void _start() = 0;
+ virtual void _pause() = 0;
+ virtual bool _isPaused() const = 0;
+
+ void showHighscores(QWidget *parent);
+
+protected:
+ virtual void _showHighscores(QWidget *parent);
+};
+
+#endif
diff --git a/libksirtet/base/kzoommainwindow.cpp b/libksirtet/base/kzoommainwindow.cpp
new file mode 100644
index 00000000..115d5175
--- /dev/null
+++ b/libksirtet/base/kzoommainwindow.cpp
@@ -0,0 +1,115 @@
+/*
+ This file is part of the KDE games library
+ Copyright (C) 2004 Nicolas Hadacek (hadacek@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kzoommainwindow.h"
+#include "kzoommainwindow.moc"
+
+#include <kaction.h>
+#include <kstdaction.h>
+#include <kmenubar.h>
+#include <kcmenumngr.h>
+
+KZoomMainWindow::KZoomMainWindow(uint min, uint max, uint step, const char *name)
+ : KMainWindow(0, name), _zoomStep(step), _minZoom(min), _maxZoom(max)
+{
+ installEventFilter(this);
+
+ _zoomInAction = KStdAction::zoomIn(this, SLOT(zoomIn()), actionCollection());
+ _zoomOutAction =
+ KStdAction::zoomOut(this, SLOT(zoomOut()), actionCollection());
+ _menu =
+ KStdAction::showMenubar(this, SLOT(toggleMenubar()), actionCollection());
+}
+
+void KZoomMainWindow::init(const char *popupName)
+{
+ // zoom
+ setZoom(readZoomSetting());
+
+ // menubar
+ _menu->setChecked( menubarVisibleSetting() );
+ toggleMenubar();
+
+ // context popup
+ if (popupName) {
+ QPopupMenu *popup =
+ static_cast<QPopupMenu *>(factory()->container(popupName, this));
+ Q_ASSERT(popup);
+ if (popup) KContextMenuManager::insert(this, popup);
+ }
+}
+
+void KZoomMainWindow::addWidget(QWidget *widget)
+{
+ widget->adjustSize();
+ QWidget *tlw = widget->topLevelWidget();
+ KZoomMainWindow *zm =
+ static_cast<KZoomMainWindow *>(tlw->qt_cast("KZoomMainWindow"));
+ Q_ASSERT(zm);
+ zm->_widgets.append(widget);
+ connect(widget, SIGNAL(destroyed()), zm, SLOT(widgetDestroyed()));
+}
+
+void KZoomMainWindow::widgetDestroyed()
+{
+ _widgets.remove(static_cast<const QWidget *>(sender()));
+}
+
+bool KZoomMainWindow::eventFilter(QObject *o, QEvent *e)
+{
+ if ( e->type()==QEvent::LayoutHint )
+ setFixedSize(minimumSize()); // because K/QMainWindow
+ // does not manage fixed central widget
+ // with hidden menubar...
+ return KMainWindow::eventFilter(o, e);
+}
+
+void KZoomMainWindow::setZoom(uint zoom)
+{
+ _zoom = zoom;
+ writeZoomSetting(_zoom);
+ QPtrListIterator<QWidget> it(_widgets);
+ for (; it.current(); ++it)
+ (*it)->adjustSize();;
+ _zoomOutAction->setEnabled( _zoom>_minZoom );
+ _zoomInAction->setEnabled( _zoom<_maxZoom );
+}
+
+void KZoomMainWindow::zoomIn()
+{
+ setZoom(_zoom + _zoomStep);
+}
+
+void KZoomMainWindow::zoomOut()
+{
+ Q_ASSERT( _zoom>=_zoomStep );
+ setZoom(_zoom - _zoomStep);
+}
+
+void KZoomMainWindow::toggleMenubar()
+{
+ if ( _menu->isChecked() ) menuBar()->show();
+ else menuBar()->hide();
+}
+
+bool KZoomMainWindow::queryExit()
+{
+ writeMenubarVisibleSetting(_menu->isChecked());
+ return KMainWindow::queryExit();
+}
diff --git a/libksirtet/base/kzoommainwindow.h b/libksirtet/base/kzoommainwindow.h
new file mode 100644
index 00000000..14f780fb
--- /dev/null
+++ b/libksirtet/base/kzoommainwindow.h
@@ -0,0 +1,128 @@
+/*
+ This file is part of the KDE games library
+ Copyright (C) 2004 Nicolas Hadacek (hadacek@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KZOOMMAINWINDOW_H
+#define KZOOMMAINWINDOW_H
+
+#include <kmainwindow.h>
+#include <kdemacros.h>
+
+
+class KToggleAction;
+
+/**
+ * KZoomMainWindow is a main window of fixed size. Its size can be
+ * modified with the "zoom in"/"zoom out" actions.
+ *
+ * It manages one or several widgets: their adjustSize() method is
+ * called whenever the zoom level is changed.
+ * The usual implementation for those widget is to redefine adjustSize()
+ * with code like:
+ * /code
+ * setFixedSize(newsize);
+ * /endcode
+ *
+ * This class also has a "show/hide menubar" action and allows the use
+ * of a context popup menu (useful to restore the menubar when hidden).
+ */
+class KDE_EXPORT KZoomMainWindow : public KMainWindow
+{
+ Q_OBJECT
+public:
+ /** Constructor. */
+ KZoomMainWindow(uint minZoom, uint maxZoom, uint zoomStep,
+ const char *name = 0);
+
+ /** Add a widget to be managed i.e. the adjustSize() method of the
+ * widget is called whenever the zoom is changed.
+ * This function assumes that the topLevelWidget() is the KZoomMainWindow.
+ */
+ static void addWidget(QWidget *widget);
+
+ uint zoom() const { return _zoom; }
+
+public slots:
+ void zoomIn();
+ void zoomOut();
+ void toggleMenubar();
+
+protected:
+ /** You need to call this after the createGUI or setupGUI method
+ * is called.
+ * @param popupName is the name of the context popup menu as defined in
+ * the ui.rc file.
+ */
+ void init(const char *popupName = 0);
+
+ virtual void setZoom(uint zoom);
+ virtual bool eventFilter(QObject *o, QEvent *e);
+ virtual bool queryExit();
+
+ /** You need to implement this method since different application
+ * use different setting class names and keys.
+ * Use something like:
+ * /code
+ * Settings::setZoom(zoom);
+ * Settings::writeConfig();
+ * /endcode
+ */
+ virtual void writeZoomSetting(uint zoom) = 0;
+
+ /** Youneed to implement this method since different application
+ * use different setting class names and keys.
+ * Use something like:
+ * /code
+ * return Settings::zoom();
+ * /endcode
+ */
+ virtual uint readZoomSetting() const = 0;
+
+ /** You need to implement this method since different application
+ * use different setting class names and keys.
+ * Use something like:
+ * /code
+ * Settings::setMenubarVisible(visible);
+ * Settings::writeConfig();
+ * /endcode
+ */
+ virtual void writeMenubarVisibleSetting(bool visible) = 0;
+
+ /** You need to implement this method since different application
+ * use different setting class names and keys.
+ * Use something like:
+ * /code
+ * Settings::menubarVisible();
+ * /endcode
+ */
+ virtual bool menubarVisibleSetting() const = 0;
+
+private slots:
+ void widgetDestroyed();
+
+private:
+ uint _zoom, _zoomStep, _minZoom, _maxZoom;
+ QPtrList<QWidget> _widgets;
+ KAction *_zoomInAction, *_zoomOutAction;
+ KToggleAction *_menu;
+
+ class KZoomMainWindowPrivate;
+ KZoomMainWindowPrivate *d;
+};
+
+#endif
diff --git a/libksirtet/base/libksirtet1.kcfg b/libksirtet/base/libksirtet1.kcfg
new file mode 100644
index 00000000..684de57f
--- /dev/null
+++ b/libksirtet/base/libksirtet1.kcfg
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <include>factory.h</include>
+ <include>piece.h</include>
+ <group name="Options">
+ <entry name="BlockSize" type="Int" key="block size">
+ <label>Size of the blocks.</label>
+ <min>4</min>
+ <max>100</max>
+ <default>15</default>
+ </entry>
+ <entry name="FadeIntensity" type="Double" key="fade intensity">
+ <label>Fade intensity.</label>
+ <default>1.0</default>
+ </entry>
+ <entry name="FadeColor" type="Color" key="fade color">
+ <label>Fade color.</label>
+ <default>black</default>
+ </entry>
+ <entry name="AnimationsEnabled" type="Bool" key="enable animations">
+ <label>Animations enabled.</label>
+ <default>true</default>
+ </entry>
+ <entry name="MenubarVisible" type="Bool" key="menubar visible">
+ <label>Menubar visible.</label>
+ <default>true</default>
+ </entry>
+ <entry name="Color$(Number)" type="Color" key="color #$(Number)">
+ <parameter name="Number" type="Int" max="10"/>
+ <label>Block colors.</label>
+<!-- TODO: max, default is dynamic -->
+ <default code="true">Piece::info().defaultColor($(Number))</default>
+ </entry>
+ </group>
+</kcfg>
diff --git a/libksirtet/base/main.cpp b/libksirtet/base/main.cpp
new file mode 100644
index 00000000..4b5a4160
--- /dev/null
+++ b/libksirtet/base/main.cpp
@@ -0,0 +1,131 @@
+#include "main.h"
+#include "main.moc"
+
+#include <kaction.h>
+#include <kstdaction.h>
+#include <kmenubar.h>
+#include <kstdgameaction.h>
+#include <kcmenumngr.h>
+#include <kkeydialog.h>
+#include <klocale.h>
+#include <knotifyclient.h>
+#include <knotifydialog.h>
+#include <kexthighscore.h>
+#include <kconfigdialog.h>
+
+#include "inter.h"
+#include "factory.h"
+#include "settings.h"
+#include "baseprefs.h"
+
+BaseMainWindow::BaseMainWindow()
+ : KZoomMainWindow(4, 100, 1, "main_window")
+{
+ KNotifyClient::startDaemon();
+
+ // File & Popup
+ KStdGameAction::gameNew(this, SLOT(start()), actionCollection());
+ _pause = KStdGameAction::pause(this, SLOT(pause()), actionCollection());
+ _pause->setEnabled(false);
+ KStdGameAction::highscores(this, SLOT(showHighscores()),
+ actionCollection());
+ KStdGameAction::quit(qApp, SLOT(quit()), actionCollection());
+
+ // Settings
+ KStdAction::preferences(this, SLOT(configureSettings()),
+ actionCollection());
+ KStdAction::keyBindings(this, SLOT(configureKeys()), actionCollection());
+ KStdAction::configureNotifications(this, SLOT(configureNotifications()),
+ actionCollection());
+ KStdGameAction::configureHighscores(this, SLOT(configureHighscores()),
+ actionCollection());
+
+ _inter = bfactory->createInterface(this);
+}
+
+void BaseMainWindow::buildGUI(QWidget *widget)
+{
+ createGUI();
+ setCentralWidget(widget);
+ init("popup");
+}
+
+BaseMainWindow::~BaseMainWindow()
+{
+ delete _inter;
+}
+
+void BaseMainWindow::showHighscores()
+{
+ _inter->showHighscores(this);
+}
+
+void BaseMainWindow::start()
+{
+ _inter->_start();
+}
+
+void BaseMainWindow::pause()
+{
+ _inter->_pause();
+}
+
+void BaseMainWindow::configureHighscores()
+{
+ KExtHighscore::configure(this);
+}
+
+void BaseMainWindow::configureSettings()
+{
+ if ( !_inter->_isPaused() ) _inter->_pause();
+ if ( KConfigDialog::showDialog("settings") ) return;
+
+ KConfigDialog *dialog = new KConfigDialog(this, "settings", BasePrefs::self() );
+ QWidget *w = bfactory->createGameConfig();
+ if (w) dialog->addPage(w, i18n("Game"), "package_system");
+ w = bfactory->createAppearanceConfig();
+ if (w) dialog->addPage(w, i18n("Appearance"), "style");
+ w = bfactory->createColorConfig();
+ if (w) dialog->addPage(w, i18n("Colors"), "colorize");
+// dialog->addPage(new BackgroundConfigWidget, i18n("Background"), "background");
+ addConfig(dialog);
+ connect(dialog, SIGNAL(settingsChanged()), SIGNAL(settingsChanged()));
+ dialog->show();
+}
+
+void BaseMainWindow::configureKeys()
+{
+ KKeyDialog d(true, this);
+ addKeys(d);
+ d.insert(actionCollection());
+ d.configure(false);
+ actionCollection()->writeShortcutSettings();
+ saveKeys();
+}
+
+void BaseMainWindow::configureNotifications()
+{
+ KNotifyDialog::configure(this);
+}
+
+void BaseMainWindow::writeZoomSetting(uint zoom)
+{
+ BasePrefs::setBlockSize(zoom);
+ BasePrefs::writeConfig();
+}
+
+uint BaseMainWindow::readZoomSetting() const
+{
+ return BasePrefs::blockSize();
+}
+
+void BaseMainWindow::writeMenubarVisibleSetting(bool visible)
+{
+ BasePrefs::setMenubarVisible(visible);
+ BasePrefs::writeConfig();
+}
+
+bool BaseMainWindow::menubarVisibleSetting() const
+{
+ return BasePrefs::menubarVisible();
+}
diff --git a/libksirtet/base/main.h b/libksirtet/base/main.h
new file mode 100644
index 00000000..d2e108aa
--- /dev/null
+++ b/libksirtet/base/main.h
@@ -0,0 +1,49 @@
+#ifndef BASE_MAIN_H
+#define BASE_MAIN_H
+
+#include "kzoommainwindow.h"
+
+#include <kdemacros.h>
+
+class BaseInterface;
+class KToggleAction;
+class KKeyDialog;
+class KConfigDialog;
+
+class KDE_EXPORT BaseMainWindow : public KZoomMainWindow
+{
+ Q_OBJECT
+public:
+ BaseMainWindow();
+ virtual ~BaseMainWindow();
+
+signals:
+ void settingsChanged();
+
+private slots:
+ void start();
+ void pause();
+ void showHighscores();
+ void configureSettings();
+ void configureKeys();
+ void configureHighscores();
+ void configureNotifications();
+
+protected:
+ BaseInterface *_inter;
+
+ void buildGUI(QWidget *widget);
+ virtual void addConfig(KConfigDialog *) {}
+ virtual void addKeys(KKeyDialog &) {}
+ virtual void saveKeys() {}
+
+ virtual void writeZoomSetting(uint zoom);
+ virtual uint readZoomSetting() const;
+ virtual void writeMenubarVisibleSetting(bool visible);
+ virtual bool menubarVisibleSetting() const;
+
+private:
+ KToggleAction *_pause;
+};
+
+#endif
diff --git a/libksirtet/base/piece.cpp b/libksirtet/base/piece.cpp
new file mode 100644
index 00000000..25aed934
--- /dev/null
+++ b/libksirtet/base/piece.cpp
@@ -0,0 +1,274 @@
+#include "piece.h"
+
+#include <kglobal.h>
+#include <krandomsequence.h>
+
+#include "baseprefs.h"
+
+using namespace KGrid2D;
+
+QPoint operator *(const Coord &c, int i)
+{
+ return QPoint(c.first * i, c.second * i);
+}
+
+//-----------------------------------------------------------------------------
+GPieceInfo::GPieceInfo()
+{
+ Piece::setPieceInfo(this);
+}
+
+QPixmap *GPieceInfo::pixmap(uint blockSize, uint blockType, uint blockMode,
+ bool lighted) const
+{
+ QPixmap *pixmap = new QPixmap(blockSize, blockSize);
+ draw(pixmap, blockType, blockMode, lighted);
+ setMask(pixmap, blockMode);
+ return pixmap;
+}
+
+Coord GPieceInfo::maxSize() const
+{
+ Coord min, max;
+ Coord size(0, 0);
+ for (uint n=0; n<nbForms(); n++) {
+ min = max = Coord(i(n, 0)[0], j(n, 0)[0]);
+ for (uint k=0; k<nbBlocks(); k++) {
+ Coord tmp = Coord(i(n, 0)[k], j(n, 0)[k]);
+ max = maximum(max, tmp);
+ min = minimum(min, tmp);
+ }
+ size = maximum(size, max - min);
+ }
+ return size;
+}
+
+uint GPieceInfo::generateType(KRandomSequence *random) const
+{
+ return random->getLong( nbTypes() );
+}
+
+uint GPieceInfo::generateGarbageBlockType(KRandomSequence *random) const
+{
+ return nbNormalBlockTypes() + random->getLong( nbGarbageBlockTypes() );
+}
+
+void GPieceInfo::loadColors()
+{
+ _colors.resize(nbColors());
+ for (uint i=0; i<_colors.size(); i++)
+ _colors[i] = BasePrefs::color(i);
+}
+
+
+//-----------------------------------------------------------------------------
+SequenceArray::SequenceArray()
+: _size(0)
+{
+ const GPieceInfo &pinfo = Piece::info();
+ fill(0, pinfo.nbNormalBlockTypes() + pinfo.nbGarbageBlockTypes());
+}
+
+void SequenceArray::setBlockSize(uint bsize)
+{
+ _size = bsize;
+ const GPieceInfo &pinfo = Piece::info();
+ QPtrList<QPixmap> pixmaps;
+ pixmaps.setAutoDelete(TRUE);
+ QPtrList<QPoint> points;
+ points.setAutoDelete(TRUE);
+ uint nm = pinfo.nbBlockModes();
+ for (uint i=0; i<size(); i++) {
+ for (uint k=0; k<2; k++)
+ for (uint j=0; j<nm; j++) {
+ QPoint *po = new QPoint(0, 0);
+ QPixmap *pi = pinfo.pixmap(bsize, i, j, k==1);
+ if ( at(i) ) {
+ at(i)->setImage(k*nm + j, new QCanvasPixmap(*pi, *po));
+ delete po;
+ delete pi;
+ } else {
+ points.append(po);
+ pixmaps.append(pi);
+ }
+ }
+ if ( at(i)==0 ) {
+ at(i) = new QCanvasPixmapArray(pixmaps, points);
+ pixmaps.clear();
+ points.clear();
+ }
+ }
+}
+
+SequenceArray::~SequenceArray()
+{
+ for (uint i=0; i<size(); i++) delete at(i);
+}
+
+//-----------------------------------------------------------------------------
+BlockInfo::BlockInfo(const SequenceArray &s)
+: _sequences(s)
+{}
+
+QPoint BlockInfo::toPoint(const Coord &pos) const
+{
+ return pos * _sequences.blockSize();
+}
+
+//-----------------------------------------------------------------------------
+Block::Block(uint value)
+: _value(value), _sprite(0)
+{}
+
+Block::~Block()
+{
+ delete _sprite;
+}
+
+void Block::setValue(uint value, BlockInfo *binfo)
+{
+ _value = value;
+ if (binfo) {
+ QCanvasPixmapArray *seq = binfo->sequences()[value];
+ if (_sprite) _sprite->setSequence(seq);
+ else {
+ _sprite = new QCanvasSprite(seq, binfo);
+ _sprite->setZ(0);
+ }
+ }
+}
+
+void Block::toggleLight()
+{
+ const GPieceInfo &pinfo = Piece::info();
+ uint f = _sprite->frame() + pinfo.nbBlockModes()
+ * (_sprite->frame()>=(int)pinfo.nbBlockModes() ? -1 : 1);
+ _sprite->setFrame(f);
+}
+
+bool Block::isGarbage() const
+{
+ return Piece::info().isGarbage(_value);
+}
+
+
+//-----------------------------------------------------------------------------
+GPieceInfo *Piece::_info = 0;
+
+Piece::Piece()
+ : _binfo(0), _i(0), _j(0)
+{
+ _blocks.setAutoDelete(true);
+}
+
+void Piece::rotate(bool left, const QPoint &p)
+{
+ if (left) {
+ if ( _rotation==0 ) _rotation = 3;
+ else _rotation--;
+ } else {
+ if ( _rotation==3 ) _rotation = 0;
+ else _rotation++;
+ }
+
+ uint form = _info->form(_type);
+ _i = _info->i(form, _rotation);
+ _j = _info->j(form, _rotation);
+ if (_binfo) move(p);
+}
+
+Coord Piece::min() const
+{
+ if ( _i==0 || _j==0 ) return Coord(0, 0);
+ Coord min = coord(0);
+ for(uint k=1; k<_info->nbBlocks(); k++)
+ min = minimum(min, coord(k));
+ return min;
+}
+
+Coord Piece::max() const
+{
+ if ( _i==0 || _j==0 ) return Coord(0, 0);
+ Coord max = coord(0);
+ for(uint k=1; k<_info->nbBlocks(); k++)
+ max = maximum(max, coord(k));
+ return max;
+}
+
+void Piece::copy(const Piece *p)
+{
+ if ( p->_blocks.size()!=0 ) {
+ _blocks.resize(p->_blocks.size());
+ for (uint k=0; k<_blocks.size(); k++) {
+ if ( _blocks[k]==0 ) _blocks.insert(k, new Block);
+ _blocks[k]->setValue(p->_blocks[k]->value(), _binfo);
+ }
+ }
+ _type = p->_type;
+ _random = p->_random;
+ _rotation = p->_rotation;
+ _i = p->_i;
+ _j = p->_j;
+}
+
+void Piece::generateNext(int type)
+{
+ if ( _blocks.size()==0 ) {
+ _blocks.resize(_info->nbBlocks());
+ for (uint k=0; k<_blocks.size(); k++) _blocks.insert(k, new Block);
+ }
+ _type = (type==-1 ? _info->generateType(_random) : (uint)type );
+ _rotation = 0;
+
+ uint form = _info->form(_type);
+ _i = _info->i(form, _rotation);
+ _j = _info->j(form, _rotation);
+
+ for (uint k=0; k<_blocks.size(); k++)
+ _blocks[k]->setValue(_info->value(_type, k), _binfo);
+}
+
+void Piece::moveCenter()
+{
+ uint s = _binfo->sequences().blockSize();
+ QPoint p = QPoint(_binfo->width(), _binfo->height()) - size() * s;
+ move(p/2 - min() * s);
+}
+
+Coord Piece::pos(uint k, const Coord &pos) const
+{
+ return Coord(pos.first + coord(k).first, pos.second - coord(k).second);
+}
+
+void Piece::move(const QPoint &p)
+{
+ for (uint k=0; k<_blocks.size(); k++) moveBlock(k, p);
+}
+
+void Piece::moveBlock(uint k, const QPoint &p)
+{
+ QPoint po = p + _binfo->toPoint(coord(k));
+ _blocks[k]->sprite()->move(po.x(), po.y());
+}
+
+Block *Piece::garbageBlock() const
+{
+ Block *b = new Block;
+ b->setValue(_info->generateGarbageBlockType(_random), _binfo);
+ return b;
+}
+
+Block *Piece::takeBlock(uint k)
+{
+ Block *b = _blocks.take(k);
+ _blocks.insert(k, new Block);
+ return b;
+}
+
+void Piece::show(bool show)
+{
+ for (uint k=0; k<_blocks.size(); k++) {
+ if (show) _blocks[k]->sprite()->show();
+ else _blocks[k]->sprite()->hide();
+ }
+}
diff --git a/libksirtet/base/piece.h b/libksirtet/base/piece.h
new file mode 100644
index 00000000..4c0486a8
--- /dev/null
+++ b/libksirtet/base/piece.h
@@ -0,0 +1,155 @@
+#ifndef BASE_PIECE_H
+#define BASE_PIECE_H
+
+#include <qcanvas.h>
+#include <qptrvector.h>
+
+#include <kgrid2d.h>
+
+
+class KRandomSequence;
+
+//-----------------------------------------------------------------------------
+class GPieceInfo
+{
+ public:
+ GPieceInfo();
+ virtual ~GPieceInfo() {}
+
+ virtual uint nbBlocks() const = 0; // nb of blocks in a piece
+ virtual uint nbTypes() const = 0; // nb of combin. of types in piece
+ virtual uint nbForms() const = 0; // nb of geometrical form of piece
+
+ virtual const int *i(uint form, uint rotation) const = 0;
+ virtual const int *j(uint form, uint rotation) const = 0;
+ virtual uint value(uint type, uint n) const = 0;
+ virtual uint form(uint type) const = 0;
+ virtual uint nbConfigurations(uint type) const = 0;
+ uint generateType(KRandomSequence *) const;
+
+ KGrid2D::Coord maxSize() const;
+
+ QPixmap *pixmap(uint blockSize, uint blockType, uint blockMode,
+ bool lighted) const;
+
+ virtual uint nbNormalBlockTypes() const = 0;
+ virtual uint nbGarbageBlockTypes() const = 0;
+ virtual uint nbBlockModes() const = 0; // nb of modes per block
+ bool isGarbage(uint type) const { return type>=nbNormalBlockTypes(); }
+ uint generateGarbageBlockType(KRandomSequence *) const;
+
+ virtual uint nbColors() const = 0;
+ virtual QString colorLabel(uint i) const = 0;
+ QCString colorKey(uint i) const;
+ virtual QColor defaultColor(uint i) const = 0;
+ void loadColors();
+
+ protected:
+ QColor color(uint i) const { return _colors[i]; }
+
+ virtual void draw(QPixmap *, uint blockType, uint blockMode,
+ bool lighted) const = 0;
+ virtual void setMask(QPixmap *, uint /*blockMode*/) const {}
+
+ private:
+ QValueVector<QColor> _colors;
+};
+
+class SequenceArray : public QMemArray<QCanvasPixmapArray *>
+{
+ public:
+ SequenceArray();
+ ~SequenceArray();
+
+ void setBlockSize(uint size);
+ uint blockSize() const { return _size; }
+
+ private:
+ uint _size;
+};
+
+//-----------------------------------------------------------------------------
+class BlockInfo : public QCanvas
+{
+ public:
+ BlockInfo(const SequenceArray &);
+ const SequenceArray &sequences() const { return _sequences; }
+
+ QPoint toPoint(const KGrid2D::Coord &) const;
+
+ private:
+ const SequenceArray &_sequences;
+};
+
+//-----------------------------------------------------------------------------
+class Block
+{
+ public:
+ Block(uint value = 0);
+ ~Block();
+
+ void setValue(uint, BlockInfo *);
+ uint value() const { return _value; }
+ bool isGarbage() const;
+ void toggleLight();
+ QCanvasSprite *sprite() const { return _sprite; }
+
+ private:
+ uint _value;
+ QCanvasSprite *_sprite;
+
+ Block(const Block &); // disabled
+ Block &operator =(const Block &); // disabled
+};
+
+//-----------------------------------------------------------------------------
+class Piece
+{
+ public:
+ Piece();
+
+ void copy(const Piece *);
+ void setBlockInfo(BlockInfo *bi) { _binfo = bi; }
+ static void setPieceInfo(GPieceInfo *pi) { _info = pi; }
+ static GPieceInfo &info() { return *_info; }
+
+ uint type() const { return _type; }
+ uint nbBlocks() const { return _blocks.size(); }
+ uint nbConfigurations() const { return _info->nbConfigurations(_type); }
+
+ int value(uint k) const { return _blocks[k]->value(); }
+ KGrid2D::Coord pos(uint k, const KGrid2D::Coord &) const;
+
+ KGrid2D::Coord min() const;
+ KGrid2D::Coord max() const;
+ KGrid2D::Coord size() const { return max() - min() + KGrid2D::Coord(1, 1); }
+
+ void generateNext(int type = -1);
+ void rotate(bool left, const QPoint &);
+ void move(const QPoint &);
+ void moveCenter();
+ void show(bool show);
+
+ void setRandomSequence(KRandomSequence *random) { _random = random; }
+
+ Block *garbageBlock() const;
+ Block *takeBlock(uint k);
+
+ private:
+ QPtrVector<Block> _blocks;
+ uint _type;
+ KRandomSequence *_random;
+ static GPieceInfo *_info;
+ BlockInfo *_binfo;
+ uint _rotation;
+ int const *_i;
+ int const *_j;
+
+ Piece(const Piece &); // disabled
+ Piece &operator =(const Piece &); // disabled
+
+ KGrid2D::Coord coord(uint k) const { return KGrid2D::Coord(_i[k], _j[k]); }
+ void moveBlock(uint k, const QPoint &);
+};
+
+#endif
diff --git a/libksirtet/base/settings.cpp b/libksirtet/base/settings.cpp
new file mode 100644
index 00000000..1ea3b16a
--- /dev/null
+++ b/libksirtet/base/settings.cpp
@@ -0,0 +1,84 @@
+#include "settings.h"
+#include "settings.moc"
+
+#include <qlabel.h>
+#include <qhbox.h>
+#include <qlayout.h>
+#include <qcheckbox.h>
+#include <qhgroupbox.h>
+
+#include <klocale.h>
+#include <knuminput.h>
+#include <kcolorbutton.h>
+#include <kapplication.h>
+#include <kdialogbase.h>
+
+#include "piece.h"
+#include "factory.h"
+
+
+//-----------------------------------------------------------------------------
+BaseAppearanceConfig::BaseAppearanceConfig()
+ : QWidget(0, "appearance_config")
+{
+ QVBoxLayout *top = new QVBoxLayout(this);
+
+ // upper part
+ _main = new QWidget(this);
+ top->addWidget(_main);
+ _grid = new QGridLayout(_main, 3, 2, 0, KDialog::spacingHint());
+ _grid->setColStretch(1, 1);
+
+ QCheckBox *chb =
+ new QCheckBox(i18n("Enable animations"), _main, "kcfg_AnimationsEnabled");
+ _grid->addMultiCellWidget(chb, 2, 2, 0, 1);
+
+ top->addSpacing(KDialog::spacingHint());
+
+ // lower part
+ QHGroupBox *gbox = new QHGroupBox(i18n("Background"), this);
+ top->addWidget(gbox);
+ QWidget *widget = new QWidget(gbox);
+ QGridLayout *grid =
+ new QGridLayout(widget, 2, 3, 0, KDialog::spacingHint());
+ grid->setColStretch(2, 1);
+ QLabel *label = new QLabel(i18n("Color:"), widget);
+ grid->addWidget(label, 0, 0);
+ KColorButton *cob = new KColorButton(widget, "kcfg_FadeColor");
+ cob->setFixedWidth(100);
+ grid->addWidget(cob, 0, 1);
+ label = new QLabel(i18n("Opacity:"), widget);
+ grid->addWidget(label, 1, 0);
+ KDoubleNumInput *dn = new KDoubleNumInput(widget, "kcfg_FadeIntensity");
+ dn->setRange(0.0, 1.0, 0.01);
+ grid->addMultiCellWidget(dn, 1, 1, 1, 2);
+
+ top->addStretch(1);
+}
+
+//-----------------------------------------------------------------------------
+ColorConfig::ColorConfig()
+ : QWidget(0, "color_config")
+{
+ const GPieceInfo &info = Piece::info();
+ QVBoxLayout *top = new QVBoxLayout(this);
+ uint nb = info.nbColors();
+ QGridLayout *grid = new QGridLayout(top, nb+1, 3, KDialog::spacingHint());
+ grid->setColStretch(2, 1);
+ for (uint i=0; i<nb; i++) {
+ QLabel *label = new QLabel(info.colorLabel(i), this);
+ grid->addWidget(label, i, 0);
+ KColorButton *cob = new KColorButton(this, colorKey(i));
+ cob->setFixedWidth(100);
+ grid->addWidget(cob, i, 1);
+ }
+ grid->setRowStretch(nb, 1);
+}
+
+QCString ColorConfig::colorKey(uint i)
+{
+ QCString s;
+ s.setNum(i);
+ return "kcfg_Color" + s;
+}
+
diff --git a/libksirtet/base/settings.h b/libksirtet/base/settings.h
new file mode 100644
index 00000000..c64bfd5b
--- /dev/null
+++ b/libksirtet/base/settings.h
@@ -0,0 +1,33 @@
+#ifndef BASE_SETTINGS_H
+#define BASE_SETTINGS_H
+
+#include <qwidget.h>
+#include <kconfig.h>
+
+class QGridLayout;
+
+
+//-----------------------------------------------------------------------------
+class BaseAppearanceConfig : public QWidget
+{
+ Q_OBJECT
+public:
+ BaseAppearanceConfig();
+
+protected:
+ QWidget *_main;
+ QGridLayout *_grid;
+};
+
+//-----------------------------------------------------------------------------
+class ColorConfig : public QWidget
+{
+ Q_OBJECT
+public:
+ ColorConfig();
+
+private:
+ static QCString colorKey(uint i);
+};
+
+#endif