/*************************************************************************** Description : KPuzzle - A KDE Jigsaw Puzzle Game Version : 0.2 Copyright : (C) 2000-2001 by Michael Wand EMail : mwand@gmx.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "main.h" #include #include #include #include #include #include #include #include #include #include #include "kpuzzle.h" #include "kpuzzleview.h" #include "gamewidget.h" #include "kpuzzlegame.h" #include "piecewidget.h" #include "picview.h" #include "gamedialog.h" #include "highscore.h" /* Constructor */ KPuzzleView::KPuzzleView(QWidget *parent, const char *name) : QWidget(parent, name) { setFixedSize(800,600); _game = NULL; _largePxm = NULL; _logoPxm = NULL; _bigLogoPxm = NULL; _winPxm = NULL; _losePxm = NULL; _pausePxm = NULL; _backgroundPxm = NULL; _usedGamePixmaps = 0; if (KGlobal::config()->readNumEntry("ImageLoading",SV_IMAGE_LOADING) == IL_PRELOAD) QTimer::singleShot(0,this,SLOT(slotLoadBackgroundPixmap())); useGamePixmap(GP_BIGLOGO); } /* Destructor */ KPuzzleView::~KPuzzleView() { if (_logoPxm) delete _logoPxm; if (_bigLogoPxm) delete _bigLogoPxm; if (_winPxm) delete _winPxm; if (_losePxm) delete _losePxm; if (_pausePxm) delete _pausePxm; delete _game; delete _backgroundPxm; } /* Game status, little more than a shortcut for game()->status() */ int KPuzzleView::status() { if (!game()) return GS_NOT_STARTED; return game()->status(); } /* Update game widget & piece widget */ void KPuzzleView::updateAll() { _gameWidget->update(); _pieceWidget->update(); } /* Load game pixmaps. May have visible effect on slower computers */ void KPuzzleView::useGamePixmap(int which) { /* Return if the pixmap coded by "which" is already loaded. */ if (which & _usedGamePixmaps) return; /* Load the pixmap. */ switch(which) { case GP_BIGLOGO: _bigLogoPxm = new QPixmap(PICFILE("biglogo.bmp")); break; case GP_PAUSE: _pausePxm = new QPixmap(PICFILE("pause.bmp")); break; case GP_WIN: _winPxm = new QPixmap(PICFILE("win.bmp")); break; case GP_LOSE: _losePxm = new QPixmap(PICFILE("lose.bmp")); break; case GP_LOGO: _logoPxm = new QPixmap(PICFILE("logo.bmp")); break; case GP_BACKGROUND: _backgroundPxm = new QPixmap(PICFILE("background.bmp")); break; } _usedGamePixmaps |= which; } /* Unload game pixmaps. May have visible effect on slower computers */ void KPuzzleView::freeGamePixmap(int which) { if (KGlobal::config()->readNumEntry("ImageLoading",SV_IMAGE_LOADING) != IL_ON_USE) return; if (!(which & _usedGamePixmaps)) return; /* not loaded */ switch(which) { case GP_BIGLOGO: delete _bigLogoPxm; _bigLogoPxm = NULL; break; case GP_PAUSE: delete _pausePxm; _pausePxm = NULL; break; case GP_WIN: delete _winPxm; _winPxm = NULL; break; case GP_LOSE: delete _losePxm; _losePxm = NULL; break; case GP_LOGO: delete _logoPxm; _logoPxm = NULL; break; case GP_BACKGROUND: delete _backgroundPxm; _backgroundPxm = NULL; break; } _usedGamePixmaps &= ~which; } /* Create all subwidgets. */ void KPuzzleView::createPlayground(KPuzzleGame* g,bool unbearable) { _gameWidget = new KGameWidget(this); _gameWidget->setGame(g); _gameWidget->setGeometry(50,100,VISIBLE_PIXMAP_SIZE, VISIBLE_PIXMAP_SIZE); _bLeft = new QPushButton("<",this); _bLeft->setGeometry(20,100,20,VISIBLE_PIXMAP_SIZE); _bUp = new QPushButton(i18n("Up"),this); _bUp->setGeometry(50,70,VISIBLE_PIXMAP_SIZE,20); _bRight = new QPushButton(">",this); _bRight->setGeometry(510,100,20,VISIBLE_PIXMAP_SIZE); _bDown = new QPushButton(i18n("Down"),this); _bDown->setGeometry(50,560,VISIBLE_PIXMAP_SIZE,20); _gameWidget->show(); _bLeft->show(); _bRight->show(); _bUp->show(); _bDown->show(); connect(_bLeft,SIGNAL(pressed()),_gameWidget,SLOT(slotLeftPress())); connect(_bLeft,SIGNAL(released()),_gameWidget,SLOT(slotLeftRelease())); connect(_bRight,SIGNAL(pressed()),_gameWidget,SLOT(slotRightPress())); connect(_bRight,SIGNAL(released()),_gameWidget, SLOT(slotRightRelease())); connect(_bUp,SIGNAL(pressed()),_gameWidget,SLOT(slotUpPress())); connect(_bUp,SIGNAL(released()),_gameWidget,SLOT(slotUpRelease())); connect(_bDown,SIGNAL(pressed()),_gameWidget,SLOT(slotDownPress())); connect(_bDown,SIGNAL(released()),_gameWidget,SLOT(slotDownRelease())); _pieceWidget = new CPieceWidget(this); _pieceWidget->setGame(g); _pieceWidget->setGeometry(575,385,200,165); _bPrevPiece = new QPushButton(i18n("Previous"),this); _bPrevPiece->setGeometry(575,355,200,20); _bNextPiece = new QPushButton(i18n("Next"),this); _bNextPiece->setGeometry(575,561,200,20); _bTurn1 = new QPushButton("<",this); _bTurn1->setGeometry(545,385,20,80); _bTurn2 = new QPushButton(">",this); _bTurn2->setGeometry(545,470,20,80); _pieceWidget->show(); _bPrevPiece->show(); _bNextPiece->show(); if (unbearable) { _bPrevPiece->setEnabled(false); _bNextPiece->setEnabled(false); } _bTurn1->show(); _bTurn2->show(); connect(_bNextPiece,SIGNAL(clicked()),_pieceWidget, SLOT(slotNextClicked())); connect(_bPrevPiece,SIGNAL(clicked()),_pieceWidget, SLOT(slotPrevClicked())); connect(_bTurn1,SIGNAL(clicked()),_pieceWidget, SLOT(slotTurn1Clicked())); connect(_bTurn2,SIGNAL(clicked()),_pieceWidget, SLOT(slotTurn2Clicked())); _picview = new CPicview(this); _picview->setGeometry(634,125,132,99); _picview->show(); _fullview = new CPicview(this); _fullview->setGeometry(634,240,132,99); _fullview->show(); connect(_picview,SIGNAL(sigChangeViewPos(QPoint)),_gameWidget, SLOT(slotShowAt(QPoint))); connect(_picview,SIGNAL(sigChangeViewPos(QPoint)),_fullview, SLOT(slotChangeViewPos(QPoint))); connect(_fullview,SIGNAL(sigChangeViewPos(QPoint)),_gameWidget, SLOT(slotShowAt(QPoint))); connect(_fullview,SIGNAL(sigChangeViewPos(QPoint)),_picview, SLOT(slotChangeViewPos(QPoint))); connect(_gameWidget,SIGNAL(sigShowAt(QPoint)),_picview, SLOT(slotChangeViewPos(QPoint))); connect(_gameWidget,SIGNAL(sigShowAt(QPoint)),_fullview, SLOT(slotChangeViewPos(QPoint))); _score = new QLCDNumber(4,this); _score->setGeometry(634,15,84,40); _score->show(); _time = new QLCDNumber(6,this); _time->setGeometry(634,70,84,40); _time->show(); /* Choose how the background is painted */ if (KGlobal::config()->readBoolEntry("ShowBackgroundImage",SV_SHOW_BACKGROUND_IMAGE)) { useGamePixmap(GP_BACKGROUND); setBackgroundPixmap(*_backgroundPxm); } else { setBackgroundMode(PaletteDark); } } /* Destroy all subwidgets. */ void KPuzzleView::destroyPlayground() { delete _gameWidget; delete _bLeft; delete _bRight; delete _bUp; delete _bDown; delete _pieceWidget; delete _bPrevPiece; delete _bNextPiece; delete _bTurn1; delete _bTurn2; delete _picview; delete _fullview; delete _score; delete _time; if (_largePxm) delete _largePxm; _largePxm = NULL; setBackgroundMode(NoBackground); freeGamePixmap(GP_BACKGROUND); useGamePixmap(GP_BIGLOGO); } #define SHOWW(w) if (s) w->show(); else w->hide(); /* Show (hide) all subwidgets if s is true (false). This is used * when the entire widget area is used to show a picture. */ void KPuzzleView::showAll(bool s) { SHOWW(_gameWidget); SHOWW(_bLeft); SHOWW(_bUp); SHOWW(_bRight); SHOWW(_bDown); SHOWW(_pieceWidget); SHOWW(_bPrevPiece); SHOWW(_bNextPiece); SHOWW(_bTurn1); SHOWW(_bTurn2); SHOWW(_picview); SHOWW(_fullview); SHOWW(_score); SHOWW(_time); } #undef SHOWW /* Show (hide) background pixmap if s is true (false). */ void KPuzzleView::showBackground(bool s) { if(s) { /* Choose how the background is painted */ if (KGlobal::config()->readBoolEntry("ShowBackgroundImage",SV_SHOW_BACKGROUND_IMAGE)) { useGamePixmap(GP_BACKGROUND); setBackgroundPixmap(*_backgroundPxm); } else { setBackgroundMode(PaletteDark); } } else { setBackgroundMode(PaletteDark); } } /* Changes the status of menu items. enable must be an or-ed * combination of the MI_* constants defined in main.h. */ void KPuzzleView::enableMenuItems(int enable) { actSave()->setEnabled(enable & MI_SAVE_GAME); actSaveAs()->setEnabled(enable & MI_SAVE_GAME); actTerminate()->setEnabled(enable & MI_STOP_GAME); actShowLarge()->setEnabled(enable & MI_SHOW_LARGE); actShowMainPixmap()->setEnabled((enable & MI_SHOW_LARGE) && KGlobal::config()->readBoolEntry("ShowMainPixmap",SV_SHOW_MAIN_PIXMAP)); actPause()->setEnabled(enable & MI_SHOW_LARGE); } /* Change the status of the moving buttons, these are the buttons * used to change the visible part of the playing area */ void KPuzzleView::updateButtons(bool b1,bool b2,bool b3,bool b4) { _bLeft->setEnabled(b1); if (!b1 && gameWidget()->moveKeyPressed() == 1) gameWidget()->slotLeftRelease(); _bUp->setEnabled(b2); if (!b2 && gameWidget()->moveKeyPressed() == 2) gameWidget()->slotUpRelease(); _bRight->setEnabled(b3); if (!b3 && gameWidget()->moveKeyPressed() == 3) gameWidget()->slotRightRelease(); _bDown->setEnabled(b4); if (!b4 && gameWidget()->moveKeyPressed() == 4) gameWidget()->slotDownRelease(); } /* Resets all game widgets and objects to the current status of the _game. * To be called from switchCurrentGame. */ void KPuzzleView::resetAll() { _gameWidget->slotShowAt(QPoint(0,0)); _picview->slotChangeViewPos(QPoint(0,0)); _fullview->slotChangeViewPos(QPoint(0,0)); } /* Paint this widget. */ void KPuzzleView::paintEvent(QPaintEvent*) { switch (status()) { case GS_NOT_STARTED: if (_bigLogoPxm != NULL) { useGamePixmap(GP_BIGLOGO); bitBlt(this,QPoint(0,0),_bigLogoPxm, _bigLogoPxm->rect(),CopyROP,false); } return; case GS_SHOW_LARGE: case GS_SHOW_LARGE_WINNING: case GS_SHOW_LARGE_LOSING: bitBlt(this,QPoint(0,0),_largePxm, _largePxm->rect(),CopyROP,false); return; case GS_WINNING: ASSERT(_winPxm); bitBlt(this,QPoint(0,0),_winPxm,_winPxm->rect(),CopyROP,false); return; case GS_LOSING: ASSERT(_losePxm); bitBlt(this,QPoint(0,0),_losePxm,_losePxm->rect(),CopyROP,false); return; case GS_PAUSED: ASSERT(_pausePxm != NULL); bitBlt(this,QPoint(0,0),_pausePxm,_pausePxm->rect(),CopyROP,false); return; case GS_SHOW_HIGHSCORES: ASSERT(_largePxm); bitBlt(this,QPoint(0,0),_largePxm, _largePxm->rect(),CopyROP,false); return; } } /* Process a mousePressEvent. */ void KPuzzleView::mousePressEvent(QMouseEvent* e) { switch (status()) { case GS_PAUSED: game()->pause(false); update(); break; case GS_SHOW_LARGE: game()->pause(false); delete _largePxm; _largePxm = NULL; update(); break; case GS_SHOW_LARGE_WINNING: game()->setStatus(GS_SHOW_HIGHSCORES); update(); break; case GS_SHOW_LARGE_LOSING: game()->setStatus(GS_SHOW_HIGHSCORES); update(); break; case GS_LOSING: game()->setStatus(GS_SHOW_LARGE_LOSING); update(); break; case GS_WINNING: game()->setStatus(GS_SHOW_LARGE_WINNING); update(); break; default: QWidget::mousePressEvent(e); break; } } /* Create a new game structure. */ KPuzzleGame* KPuzzleView::createNewGame() { KPuzzleGame* ng = new KPuzzleGame(this); if (!ng->createNewGame()) { delete ng; return NULL; } return ng; } /* Create a new game structure suitable for * a loaded game. */ KPuzzleGame* KPuzzleView::createLoadedGame() { KPuzzleGame* ng = new KPuzzleGame(this); if (!ng->createLoadedGame()) { delete ng; return NULL; } return ng; } /* Put a game structure into use. */ void KPuzzleView::switchCurrentGame(KPuzzleGame* ng) { ASSERT(ng); /* Choose how the background is painted */ if (KGlobal::config()->readBoolEntry("ShowBackgroundImage",SV_SHOW_BACKGROUND_IMAGE)) { useGamePixmap(GP_BACKGROUND); setBackgroundPixmap(*_backgroundPxm); } else { setBackgroundMode(PaletteDark); } if (_game) delete _game; pieceWidget()->setGame(ng); gameWidget()->setGame(ng); connect(actSave(),SIGNAL(activated()),ng,SLOT(slotSaveGame())); connect(actSaveAs(),SIGNAL(activated()),ng,SLOT(slotSaveGameAs())); connect(actTerminate(),SIGNAL(activated()),ng,SLOT(slotStopGame())); connect(actShowLarge(),SIGNAL(activated()),ng,SLOT(slotShowLarge())); connect(actShowMainPixmap(),SIGNAL(activated()),ng,SLOT(slotShowMainPixmap())); connect(actPause(),SIGNAL(activated()),ng,SLOT(slotPause())); connect(ng,SIGNAL(sigUpdate()),this,SLOT(update())); connect(ng,SIGNAL(sigTerm(int)),this,SLOT(slotTerm(int))); connect(ng,SIGNAL(sigDone()),this,SLOT(slotGameIsDone())); connect(ng,SIGNAL(sigScore(int)),_score,SLOT(display(int))); setLargePxm(NULL); _picview->updatePixmap(ng->gamePixmap(),_picview->rect()); _fullview->updatePixmap(ng->mainPixmap(),_fullview->rect()); _score->display(ng->currentData()->_score); _time->display(ng->currentData()->_elapsed); _game = ng; showAll(true); resetAll(); update(); } /* Menu slot */ void KPuzzleView::slotNewGame() { bool gameIsPaused = false; if (game()) { gameIsPaused = game()->paused(); game()->pause(true); if (status() != GS_NOT_STARTED) if (KMessageBox::warningYesNo(0,i18n("A game is already running. Start a new one or return to the current?"), i18n("Stop this game?"),i18n("New Game"),i18n("Return")) == KMessageBox::No) { game()->pause(gameIsPaused); return; } } KPuzzleGame* newGame = createNewGame(); if (!newGame) { if (game()) game()->pause(gameIsPaused); return; } if (!game()) createPlayground(newGame,newGame->gameData()->_gameType == UNBEARABLE_GAME); newGame->initializeNew(); switchCurrentGame(newGame); /* destroys the old game */ update(); } /* Menu slot. */ void KPuzzleView::slotOpenGame() { bool gameIsPaused = false; if (game()) { gameIsPaused = game()->paused(); game()->pause(true); if (status() != GS_NOT_STARTED) if (KMessageBox::warningYesNo(0,i18n("A game is already running. Load a new one or return to the current?"), i18n("Load game?"),i18n("Load new"),i18n("Return")) == KMessageBox::No) { game()->pause(gameIsPaused); return; } } KPuzzleGame* newGame = createLoadedGame(); if (!newGame) { if (game()) game()->pause(gameIsPaused); return; } if (!game()) createPlayground(newGame,newGame->gameData()->_gameType == UNBEARABLE_GAME); newGame->initializeLoad(); switchCurrentGame(newGame); /* destroys the old game */ update(); } /* Called when the game should clean up, save highscores etc. */ void KPuzzleView::slotTerm(int) { } /* Called when the game object must be destroyed. */ void KPuzzleView::slotGameIsDone() { destroyPlayground(); delete _game; _game = NULL; setBackgroundMode(NoBackground); freeGamePixmap(GP_BACKGROUND); } /* Slot called on startup after the basic work is done. * Loads the background pixmap, which may theoretically * take some time. */ void KPuzzleView::slotLoadBackgroundPixmap() { useGamePixmap(GP_BIGLOGO); repaint(0,0,width(),height(),false); useGamePixmap(GP_LOGO); useGamePixmap(GP_WIN); useGamePixmap(GP_LOSE); useGamePixmap(GP_PAUSE); useGamePixmap(GP_BACKGROUND); }