Commit 054b599a authored by Nicolas Hadacek's avatar Nicolas Hadacek
Browse files

bug fixes

svn path=/trunk/kdegames/kmines/; revision=41097
parent 18f4da72
......@@ -4,7 +4,7 @@
* can choose case size (font is scaled)
* less flicker in repainting (+ fixed a strange divide negative int by
uint thing)
* fix the pixmaps drawing to be not too bad in other case sizes
* fix the pixmaps drawing so that they are not too bad in custom case sizes
2.0.0
* use of KDialogBase and KAboutData/KAboutDialog
......
- layout bug when changing level/case size (fvwm specific ?)
- when size is just changed (and hence font point size is changed), the
QPainter mess things up and do not paint some area ... (strange thing)
#include "defines.h"
#include <stdlib.h>
#include <time.h>
#include <config.h>
const char *OP_GRP = "Options";
const char *OP_UMARK = "? mark";
const char *OP_MENU = "menubar visible";
const char *OP_MENUBAR = "menubar visible";
const char *OP_LEVEL = "Level";
const char *OP_CASE_SIZE = "case size";
const char *OP_KEYBOARD = "keyboard game";
......
......@@ -6,7 +6,7 @@
/* Strings for the configuration file */
extern const char *OP_GRP;
extern const char *OP_UMARK;
extern const char *OP_MENU;
extern const char *OP_MENUBAR;
extern const char *OP_LEVEL;
extern const char *OP_CASE_SIZE;
extern const char *OP_KEYBOARD;
......
......@@ -9,7 +9,7 @@
Field::Field(QWidget *parent, const char *name)
: QFrame(parent, name), lev(LEVELS[0]), random(0),
paused(FALSE), stopped(FALSE),
left_down(FALSE), mid_down(FALSE), pt(this)
left_down(FALSE), mid_down(FALSE)
{
setFrameStyle( QFrame::Box | QFrame::Raised );
setLineWidth(2);
......@@ -23,7 +23,7 @@ Field::Field(QWidget *parent, const char *name)
connect(pb, SIGNAL(clicked()), this, SLOT(resume()));
top->addStretch(1);
pt.setFont( QFont("Helvetica", 14, QFont::Bold) );
setFont( QFont("Helvetica", 14, QFont::Bold) );
}
void Field::setCaseSize(uint cs)
......@@ -52,9 +52,9 @@ void Field::setCaseSize(uint cs)
cursorPixmap(pm_cursor, FALSE);
pm_cursor.setMask(mask);
QFont f = pt.font();
QFont f = font();
f.setPointSize(cs-6);
pt.setFont(f);
setFont(f);
updateGeometry();
}
......@@ -171,32 +171,35 @@ void Field::restart(bool repaint)
_pfield.resize( (lev.width+2) * (lev.height+2) );
QPainter *p;
if (repaint) p = new QPainter(this);
for (uint i=0; i<lev.width+2; i++)
for (uint j=0; j<lev.height+2; j++) {
uint tmp = (i==0 || i==lev.width+1 || j==0 || j==lev.height+1
? UNCOVERED : COVERED);
if ( pfield(i, j)==tmp ) continue;
pfield(i, j) = tmp;
if (repaint && tmp==COVERED) drawCase(i, j);
if (repaint && tmp==COVERED) drawCase(i, j, p);
}
if (repaint) drawCursor(FALSE);
if (repaint) drawCursor(FALSE, p);
ic = lev.width/2;
jc = lev.height/2;
if ( repaint && cursor ) drawCursor(TRUE);
if ( repaint && cursor ) drawCursor(TRUE, p);
}
void Field::paintEvent(QPaintEvent *e)
{
if (paused) return;
drawFrame(&pt);
QPainter p(this);
drawFrame(&p);
uint imin = (uint)QMAX(QMIN(xToI(e->rect().left()), (int)lev.width), 1);
uint imax = (uint)QMAX(QMIN(xToI(e->rect().right()), (int)lev.width), 1);
uint jmin = (uint)QMAX(QMIN(yToJ(e->rect().top()), (int)lev.height), 1);
uint jmax = (uint)QMAX(QMIN(yToJ(e->rect().bottom()), (int)lev.height), 1);
for (uint i=imin; i<=imax; i++)
for (uint j=jmin; j<=jmax; j++) drawCase(i, j);
for (uint j=jmin; j<=jmax; j++) drawCase(i, j, &p);
}
void Field::changeCaseState(uint i, uint j, uint new_st)
......@@ -235,49 +238,6 @@ int Field::yToJ(int y) const
return (int)((float)(y - frameWidth())/_caseSize) + 1;
}
void Field::drawCase(uint i, uint j)
{
int x = iToX(i);
int y = jToY(j);
pt.eraseRect(x, y, _caseSize, _caseSize);
bool unrevealed = pfield(i, j) & (COVERED | MARKED | UNCERTAIN | ERROR);
qDrawWinPanel(&pt, x, y, _caseSize, _caseSize, colorGroup(), !unrevealed);
if (unrevealed) {
if (pfield(i, j) & MARKED) bitBlt(this, x, y, &pm_flag);
else if (pfield(i, j) & UNCERTAIN) {
pt.setPen(black);
pt.drawText(x, y, _caseSize, _caseSize, AlignCenter, "?");
} else if (pfield(i, j) & ERROR) bitBlt(this, x, y, &pm_error);
} else {
if (pfield(i, j) & MINE) {
const QPixmap &pm
= (pfield(i, j) & EXPLODED ? pm_exploded : pm_mine);
bitBlt(this, x, y, &pm);
} else {
uint nbs = computeNeighbours(i, j);
if (nbs) {
char nb[2] = "0";
nb[0] += nbs;
switch(nbs) {
case 1: pt.setPen(blue); break;
case 2: pt.setPen(darkGreen); break;
case 3: pt.setPen(darkYellow); break;
case 4: pt.setPen(darkMagenta); break;
case 5: pt.setPen(red); break;
case 6: pt.setPen(darkRed); break;
case 7:
case 8: pt.setPen(black); break;
}
pt.drawText(x, y, _caseSize, _caseSize, AlignCenter, nb);
}
}
}
if ( cursor && (int)i==ic && (int)j==jc ) drawCursor(TRUE);
}
void Field::uncover(uint i, uint j)
{
if ( !(pfield(i, j) & COVERED) ) return;
......@@ -305,15 +265,21 @@ void Field::mousePressEvent(QMouseEvent *e)
{
if ( locked() ) return;
setMood(Smiley::Stressed);
if ( !placeCursor(xToI(e->pos().x()), yToJ(e->pos().y())) ) return;
bool inside = placeCursor(xToI(e->pos().x()), yToJ(e->pos().y()));
if ( e->button()==LeftButton ) {
switch (e->button()) {
case LeftButton:
left_down = TRUE;
pressCase(ic, jc, TRUE);
} else if ( e->button()==RightButton ) mark();
else if ( e->button()==MidButton ) {
if (inside) pressCase(ic, jc, FALSE);
break;
case RightButton:
if (inside) mark();
break;
case MidButton:
mid_down = TRUE;
pressClearFunction(ic, jc, TRUE);
if (inside) pressClearFunction(ic, jc, FALSE);
break;
default: break;
}
}
......@@ -321,16 +287,21 @@ void Field::mouseReleaseEvent(QMouseEvent *e)
{
if ( locked() ) return;
setMood(Smiley::Normal);
if ( !inside(ic, jc) ) return;
if ( e->button()==LeftButton ) {
if ( !left_down ) return;
left_down = FALSE;
if ( inside(ic, jc) )
if (mid_down) pressClearFunction(ic, jc, TRUE);
left_down = FALSE;
mid_down = FALSE;
if ( !placeCursor(xToI(e->pos().x()), yToJ(e->pos().y())) ) return;
switch (e->button()) {
case LeftButton:
reveal();
} else if ( e->button()==MidButton ) {
mid_down = FALSE;
pressClearFunction(ic, jc, FALSE);
break;
case MidButton:
autoReveal();
break;
default: break;
}
}
......@@ -339,14 +310,14 @@ void Field::mouseMoveEvent(QMouseEvent *e)
if ( locked() ) return;
if ( inside(ic, jc) ) {
if (left_down) pressCase(ic, jc, FALSE);
else if (mid_down) pressClearFunction(ic, jc, FALSE);
if (left_down) pressCase(ic, jc, TRUE);
if (mid_down) pressClearFunction(ic, jc, TRUE);
}
if ( !placeCursor(xToI(e->pos().x()), yToJ(e->pos().y())) ) return;
if (left_down) pressCase(ic, jc, TRUE);
else if (mid_down) pressClearFunction(ic, jc, TRUE);
if (left_down) pressCase(ic, jc, FALSE);
else if (mid_down) pressClearFunction(ic, jc, FALSE);
}
void Field::showMines()
......@@ -359,27 +330,23 @@ void Field::showMines()
} else if (pfield(i, j) & MARKED) changeCaseState(i, j, ERROR);
}
void Field::pressCase(uint i, uint j, uint state)
void Field::pressCase(uint i, uint j, bool pressed, QPainter *p)
{
if (pfield(i, j) & COVERED) {
int x = iToX(i);
int y = jToY(j);
pt.eraseRect(x, y, _caseSize, _caseSize);
qDrawWinPanel(&pt, x, y, _caseSize, _caseSize, colorGroup(), state);
}
if (pfield(i, j) & COVERED) drawBox(iToX(i), jToY(j), pressed, p);
}
void Field::pressClearFunction(uint i, uint j, uint state)
void Field::pressClearFunction(uint i, uint j, bool pressed)
{
pressCase(i-1, j+1, state);
pressCase(i-1, j, state);
pressCase(i-1, j-1, state);
pressCase( i, j+1, state);
pressCase( i, j, state);
pressCase( i, j-1, state);
pressCase(i+1, j-1, state);
pressCase(i+1, j, state);
pressCase(i+1, j+1, state);
QPainter p(this);
pressCase(i-1, j+1, pressed, &p);
pressCase(i-1, j, pressed, &p);
pressCase(i-1, j-1, pressed, &p);
pressCase( i, j+1, pressed, &p);
pressCase( i, j, pressed, &p);
pressCase( i, j-1, pressed, &p);
pressCase(i+1, j-1, pressed, &p);
pressCase(i+1, j, pressed, &p);
pressCase(i+1, j+1, pressed, &p);
}
#define M_OR_U(i, j) ( (pfield(i, j) & MARKED) || (pfield(i, j) & UNCERTAIN) )
......@@ -435,8 +402,7 @@ void Field::pause()
if ( paused ) resume();
else {
emit freezeTimer();
pt.eraseRect(0, 0, width(), height());
eraseField();
emit putMsg(i18n("Game paused"));
pb->show();
pb->setFocus();
......@@ -511,30 +477,99 @@ void Field::mark()
bool Field::placeCursor(int i, int j, bool check)
{
if ( check && (locked() || !inside(i, j)) ) return FALSE;
if (cursor) drawCursor(FALSE);
if ( cursor && inside(ic, jc) ) drawCursor(FALSE);
ic = i;
jc = j;
if ( !check && !inside(i, j) ) return FALSE;
if ( !inside(i, j) ) return FALSE;
if (cursor) drawCursor(TRUE);
return TRUE;
}
void Field::drawCursor(bool show)
{
if (show) bitBlt(this, iToX(ic), jToY(jc), &pm_cursor);
else {
bool b = cursor;
if (b) cursor = FALSE;
drawCase(ic, jc);
if (b) cursor = TRUE;
}
}
void Field::setCursor(bool show)
{
if ( !locked() ) {
if ( !locked() && inside(ic, jc) ) {
if ( cursor && !show ) drawCursor(FALSE);
if ( !cursor && show) drawCursor(TRUE);
}
cursor = show;
}
// draw methods
QPainter *Field::begin(QPainter *pt)
{
return (pt ? pt : new QPainter(this));
}
void Field::end(QPainter *p, const QPainter *pt)
{
if (pt==0) delete p;
}
void Field::drawBox(int x, int y, bool pressed, QPainter *pt)
{
QPainter *p = begin(pt);
p->eraseRect(x, y, _caseSize, _caseSize);
qDrawWinPanel(p, x, y, _caseSize, _caseSize, colorGroup(), !pressed);
end(p, pt);
}
void Field::drawCase(uint i, uint j, QPainter *pt)
{
QPainter *p = begin(pt);
int x = iToX(i);
int y = jToY(j);
bool covered = pfield(i, j) & (COVERED | MARKED | UNCERTAIN | ERROR);
drawBox(x, y, covered, p);
if (covered) {
if (pfield(i, j) & MARKED) p->drawPixmap(x, y, pm_flag);
else if (pfield(i, j) & UNCERTAIN) {
p->setPen(black);
p->drawText(x, y, _caseSize, _caseSize, AlignCenter, "?");
} else if (pfield(i, j) & ERROR) p->drawPixmap(x, y, pm_error);
} else {
if (pfield(i, j) & MINE)
p->drawPixmap(x, y, (pfield(i, j) & EXPLODED ? pm_exploded
: pm_mine));
else {
uint nbs = computeNeighbours(i, j);
if (nbs) {
char nb[2] = "0";
nb[0] += nbs;
switch(nbs) {
case 1: p->setPen(blue); break;
case 2: p->setPen(darkGreen); break;
case 3: p->setPen(darkYellow); break;
case 4: p->setPen(darkMagenta); break;
case 5: p->setPen(red); break;
case 6: p->setPen(darkRed); break;
case 7:
case 8: p->setPen(black); break;
}
p->drawText(x, y, _caseSize, _caseSize, AlignCenter, nb);
}
}
}
if ( cursor && (int)i==ic && (int)j==jc ) drawCursor(TRUE, p);
end(p, pt);
}
void Field::eraseField()
{
QPainter p(this);
p.eraseRect(0, 0, width(), height());
}
void Field::drawCursor(bool show, QPainter *pt)
{
QPainter *p = begin(pt);
if (show) p->drawPixmap(iToX(ic), jToY(jc), pm_cursor);
else {
bool b = cursor;
if (b) cursor = FALSE;
drawCase(ic, jc, p);
if (b) cursor = TRUE;
}
end(p, pt);
}
......@@ -73,21 +73,18 @@ class Field : public QFrame
bool mid_down; // mid button pressed
uint _caseSize;
QPainter pt;
QPixmap pm_flag, pm_mine, pm_exploded, pm_error, pm_cursor;
QPushButton *pb;
uint computeNeighbours(uint, uint) const;
void drawCase(uint, uint);
void uncover(uint, uint);
void changeCaseState(uint, uint, uint);
void minePixmap(QPixmap &, bool mask, uint type) const;
void pressCase(uint, uint, uint);
void pressClearFunction(uint, uint, uint);
void pressCase(uint, uint, bool, QPainter * = 0);
void pressClearFunction(uint, uint, bool);
void uncoverCase(uint, uint);
bool inside(int, int) const;
bool placeCursor(int, int, bool check = FALSE);
void drawCursor(bool show);
void flagPixmap(QPixmap &, bool mask) const;
void cursorPixmap(QPixmap &, bool mask) const;
bool locked() const { return stopped || paused; }
......@@ -97,6 +94,13 @@ class Field : public QFrame
int yToJ(int y) const;
int iToX(uint i) const;
int jToY(uint j) const;
QPainter *begin(QPainter *);
void end(QPainter *, const QPainter *);
void drawCase(uint, uint, QPainter * = 0);
void drawBox(int, int, bool, QPainter * = 0);
void eraseField();
void drawCursor(bool show, QPainter * = 0);
};
#endif // FIELD_H
......@@ -8,53 +8,51 @@
#include <klocale.h>
#include <kglobal.h>
#include <kconfig.h>
#include <kaboutdialog.h>
#include <kcmdlineargs.h>
#include <kaboutdata.h>
#include <kmenubar.h>
#include <khelpmenu.h>
#include <kstdaction.h>
#include "defines.h"
#include "version.h"
#include "status.h"
MainWidget::MainWidget()
MainWidget::MainWidget(const KAboutData *aboutData)
: keyAction(7), levelAction(NbLevels)
{
installEventFilter(this);
status = new Status(this);
status->installEventFilter(this);
kacc = new KAccel(this);
// popup
popup = new KActionMenu(i18n("&File"), this);
menuBar()->insertItem(i18n("&File"), popup->popupMenu());
menuAction = new KToggleAction(QString::null, 0,
this, SLOT(toggleMenu()), this);
menuBar()->insertItem(popup->text(), popup->popupMenu());
menuAction = new KAction(QString::null, 0,
this, SLOT(toggleMenu()), this);
popup->insert(menuAction);
popup->insert( new KActionSeparator(this) );
KAction *action = new KAction(i18n("&New game"), 0,
status, SLOT(restartGame()), this);
action->plugStdAccel(kacc, KStdAccel::New);
KAction *action = KStdAction::openNew(status, SLOT(restartGame()), this);
action->setText(i18n("&New game"));
popup->insert(action);
action = new KAction(i18n("&Pause game"), Key_P,
status, SLOT(pauseGame()), this);
action->plugAccel(kacc, "pause");
popup->insert(action);
popup->insert( new KActionSeparator(this) );
action = new KAction(i18n("&High scores"), Key_H,
action = new KAction(i18n("&High scores..."), Key_H,
status, SLOT(showHighScores()), this);
action->plugAccel(kacc, "highscores");
popup->insert(action);
action = new KAction(i18n("P&rint"), 0, status, SLOT(print()), this);
action->plugStdAccel(kacc, KStdAccel::Print);
action = KStdAction::print(status, SLOT(print()), this);
popup->insert(action);
popup->insert( new KActionSeparator(this) );
action = new KAction(i18n("&Quit"), 0, qApp, SLOT(quit()), this);
action->plugStdAccel(kacc, KStdAccel::Quit);
action = KStdAction::quit(qApp, SLOT(quit()), this);
popup->insert(action);
// keyboard
keyAction[0] = new KAction(i18n("Move up"), Key_Up,
status, SLOT(moveUp()), this);
......@@ -80,30 +78,29 @@ MainWidget::MainWidget()
// options
KActionMenu *options = new KActionMenu(i18n("&Settings"), this);
menuBar()->insertItem(i18n("&Settings"), options->popupMenu());
QArray<KToggleAction *> toggleAction(2);
toggleAction[0] = new KToggleAction(i18n("? &mark"), 0,
this, SLOT(toggleUMark()), this);
options->insert(toggleAction[0]);
toggleAction[1] = new KToggleAction(i18n("keyboard play"), 0,
this, SLOT(toggleKeyboard()), this);
options->insert(toggleAction[1]);
action = new KAction(i18n("Other settings"), 0,
menuBar()->insertItem(options->text(), options->popupMenu());
KToggleAction *markAction = new KToggleAction(i18n("? &mark"), 0,
this, SLOT(toggleUMark()), this);
options->insert(markAction);
KToggleAction *keyboardAction = new KToggleAction(i18n("&keyboard play"),
0, this, SLOT(toggleKeyboard()), this);
options->insert(keyboardAction);
action = new KAction(i18n("&Other settings..."), 0,
status, SLOT(options()), this);
options->insert(action);
action = new KAction(i18n("&Keys"), 0, this, SLOT(configKeys()), this);
action = KStdAction::keyBindings(this, SLOT(configKeys()), this);
options->insert(action);
// levels
KActionMenu *levels = new KActionMenu(i18n("&Level"), this);
menuBar()->insertItem(i18n("&Level"), levels->popupMenu());
menuBar()->insertItem(levels->text(), levels->popupMenu());
levelAction[0] = new KRadioAction(i18n("&Easy"), 0,
this, SLOT(easyLevel()), this);
levelAction[1] = new KRadioAction(i18n("&Normal"), 0,
this, SLOT(normalLevel()), this);
levelAction[2] = new KRadioAction(i18n("&Expert"), 0,
this, SLOT(expertLevel()), this);
levelAction[3] = new KRadioAction(i18n("&Custom"), 0,
levelAction[3] = new KRadioAction(i18n("&Custom..."), 0,
this, SLOT(customLevel()), this);
for (uint i=0; i<levelAction.size(); i++) {
levelAction[i]->setExclusiveGroup("level");
......@@ -113,7 +110,8 @@ MainWidget::MainWidget()
// help
menuBar()->insertSeparator();
menuBar()->insertItem(i18n("&Help"), helpMenu());
KHelpMenu *help = new KHelpMenu(this, aboutData);
menuBar()->insertItem(i18n("&Help"), help->menu());
// read key settings
kacc->readSettings();
......@@ -122,8 +120,8 @@ MainWidget::MainWidget()
init = TRUE;
toggleMenu();
changeLevel(0);
toggleAction[0]->setChecked( toggleUMark() );
toggleAction[1]->setChecked( toggleKeyboard() );
markAction->setChecked( toggleUMark() );
keyboardAction->setChecked( toggleKeyboard() );
init = FALSE;
setView(status);
......@@ -172,7 +170,7 @@ bool MainWidget::toggle(const char *name)
void MainWidget::toggleMenu()
{
bool show = toggle(OP_MENU);
bool show = toggle(OP_MENUBAR);
if (show) menuBar()->show(); else menuBar()->hide();
menuAction->setText((show ? i18n("Hide menu") : i18n("Show menu")));
}
......@@ -199,15 +197,14 @@ static const char *DESCRIPTION
int main(int argc, char **argv)
{
KAboutData aboutData("kmines", I18N_NOOP("KMines"),
QString("%1 (%2/%3/%4)").arg(VERSION).arg(DAY).arg(MONTH).
arg(YEAR).latin1(), DESCRIPTION, KAboutData::License_GPL,
LONG_VERSION, DESCRIPTION, KAboutData::License_GPL,
"(c) 1996-2000, Nicolas Hadacek",
0, "http://azhyd.free.fr/KDE/kmines.php3");
aboutData.addAuthor("Nicolas Hadacek", 0, "hadacek@kde.org");
KCmdLineArgs::init(argc, argv, &aboutData);
KApplication a;
MainWidget *mw = new MainWidget;
MainWidget *mw = new MainWidget(&aboutData);
a.setMainWidget(mw);
mw->show();
return a.exec();
......
......@@ -12,7 +12,7 @@ class MainWidget : public KTMainWindow
Q_OBJECT
public:
MainWidget();
MainWidget(const KAboutData *);
private slots:
void easyLevel() { changeLevel(0); }
......@@ -33,7 +33,7 @@ class MainWidget : public KTMainWindow
KActionMenu *popup;
QArray<KAction *> keyAction;
QArray<KRadioAction *> levelAction;
KToggleAction *menuAction;
KAction *menuAction;