00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "fifteen.h"
00022
00023 #include "fifteenconfigdialog.h"
00024
00025 #include <opie2/ofileselector.h>
00026 #include <opie2/oresource.h>
00027
00028 #include <qtopia/config.h>
00029 #include <qtopia/qpeapplication.h>
00030
00031 #include <qvbox.h>
00032 #include <qaction.h>
00033 #include <qpainter.h>
00034 #include <qmessagebox.h>
00035 #include <qtoolbar.h>
00036 #include <qmenubar.h>
00037 #include <qimage.h>
00038
00039 #include <stdlib.h>
00040 #include <time.h>
00041
00042 FifteenMainWindow::FifteenMainWindow(QWidget *parent, const char* name, WFlags fl)
00043 : QMainWindow( parent, name, fl )
00044 {
00045
00046
00047 srand(time(0));
00048 setCaption( tr("Fifteen Pieces") );
00049
00050 QToolBar *toolbar = new QToolBar(this);
00051 toolbar->setHorizontalStretchable( FALSE );
00052 QMenuBar *menubar = new QMenuBar( toolbar );
00053 menubar->setMargin(0);
00054 QPopupMenu *game = new QPopupMenu( this );
00055 menubar->insertItem( tr( "Game" ), game );
00056
00057 QWidget *spacer = new QWidget( toolbar );
00058 spacer->setBackgroundMode( PaletteButton );
00059 toolbar->setStretchableWidget( spacer );
00060
00061
00062 setToolBarsMovable( FALSE );
00063 QVBox *vbox = new QVBox( this );
00064 PiecesTable *table = new PiecesTable( vbox );
00065 setCentralWidget(vbox);
00066
00067
00068
00069 QAction *a = new QAction( tr( "Randomize" ), Opie::Core::OResource::loadPixmap( "new", Opie::Core::OResource::SmallIcon ),
00070 QString::null, 0, this, 0 );
00071 connect( a, SIGNAL( activated() ), table, SLOT( slotRandomize() ) );
00072 a->addTo( game );
00073 a->addTo( toolbar );
00074
00075
00076 a = new QAction( tr("Configure"), Opie::Core::OResource::loadPixmap( "SettingsIcon", Opie::Core::OResource::SmallIcon ),
00077 QString::null, 0, this, 0 );
00078 connect( a, SIGNAL( activated()), table, SLOT( slotConfigure()) );
00079 a->addTo( game );
00080 }
00081
00082
00083
00084
00088 PiecesTable::PiecesTable(QWidget* parent, const char* name )
00089 : QTableView(parent, name), _menu(0), _randomized(false),
00090 _dialog( 0l )
00091 {
00092
00093 setFrameStyle(StyledPanel | Sunken);
00094 setBackgroundMode(NoBackground);
00095 setMouseTracking(true);
00096
00097 setNumRows(4);
00098 setNumCols(4);
00099
00100
00101 readConfig();
00102 initColors();
00103
00104 }
00105
00106
00107 PiecesTable::~PiecesTable()
00108 {
00109 writeConfig();
00110 clear();
00111 }
00112
00113 void PiecesTable::writeConfig()
00114 {
00115 Config cfg("Fifteen");
00116 cfg.setGroup("Game");
00117 QStringList map;
00118
00119 int items = numRows()*numCols();
00120
00121 for (int i = 0; i < items; i++)
00122 map.append( QString::number( _map[i] ) );
00123
00124 cfg.writeEntry("Map", map, '-');
00125 cfg.writeEntry("Randomized", _randomized );
00126 cfg.writeEntry("Image", _image );
00127 cfg.writeEntry("Rows", numRows() );
00128 cfg.writeEntry("Cols", numCols() );
00129 }
00130
00131 void PiecesTable::readConfig()
00132 {
00133 Config cfg("Fifteen");
00134 cfg.setGroup("Game");
00135 QStringList map = cfg.readListEntry("Map", '-');
00136 _randomized = cfg.readBoolEntry( "Randomized", FALSE );
00137 _image = cfg.readEntry( "Image", QString::null );
00138
00139 int rows = cfg.readNumEntry( "Rows", 4 );
00140 int cols = cfg.readNumEntry( "Cols", 4 );
00141 uint items= rows*cols;
00142 setNumRows( rows );
00143 setNumCols( cols );
00144
00145 initMap();
00146
00147
00148 if ( items > map.count() )
00149 return;
00150
00151
00152 uint i = 0;
00153 for ( QStringList::Iterator it = map.begin(); it != map.end(); ++it ) {
00154 _map[i] = (*it).toInt();
00155 i++;
00156 if ( i > items ) break;
00157 }
00158
00159 }
00160
00161
00162 void PiecesTable::clear() {
00163
00164 for (uint i = 0; i < _pixmap.count(); ++i )
00165 delete _pixmap[i];
00166 _pixmap.resize( numRows()*numCols() );
00167 }
00168
00169
00170
00171
00172
00173
00174 void PiecesTable::slotCustomImage( const QString& _str ) {
00175 QString str = _str;
00176
00177
00178
00179 QImage img = QImage(str);
00180 QPixmap pix;
00181 if(img.isNull())
00182 str = QString::null;
00183 else{
00184 img = img.smoothScale( width(),height() );
00185 pix.convertFromImage( img );
00186 }
00187
00188
00189 uint image=0;
00190
00191
00192 clear();
00193
00194
00195 int cols = numCols();
00196 int rows = numRows();
00197 int cellW = cellWidth();
00198 int cellH = cellHeight();
00199 int x2 = cellW-1;
00200 int y2 = cellH-1;
00201 bool empty = str.isEmpty();
00202 double bw = empty ? 0.9 : 0.98;
00203 int x_offset = cellW - int(cellW * bw);
00204 int y_offset = cellH - int(cellH * bw);
00205
00206
00207 initPolygon(cellW, cellH, x_offset, y_offset );
00208
00209
00210 if ( cellW == 0 || cellH == 0 ) {
00211 _pixmap.resize( 0 );
00212 return;
00213 }
00214
00215
00216 QFont f = font();
00217 f.setPixelSize(18);
00218 f.setBold( TRUE );
00219
00220
00221 for(int row = 0; row < rows; ++row ) {
00222 for(int col= 0; col < cols; ++col) {
00223 QPixmap *pip = new QPixmap(cellW, cellH );
00224 QPainter *p = new QPainter(pip );
00225 p->setFont( f );
00226
00227
00228 if(empty) {
00229 p->setBrush(_colors[image]);
00230 p->setPen(NoPen);
00231 p->drawRect(0,0,cellW,cellH);
00232 }else
00233 p->drawPixmap(0, 0, pix,col*cellW, row*cellH, cellW, cellH );
00234
00235
00236 if (height() > 40) {
00237 p->setBrush(_colors[image].light(130));
00238 p->drawPolygon(light_border);
00239
00240 p->setBrush(_colors[image].dark(130));
00241 p->drawPolygon(dark_border);
00242 }
00243
00244
00245 p->setPen(black);
00246 p->drawText(0, 0, x2, y2, AlignHCenter | AlignVCenter, QString::number(image+1));
00247
00248 delete p;
00249 _pixmap[image++] = pip;
00250 }
00251 }
00252 _image = str;
00253 }
00254
00255
00256
00257
00258 void PiecesTable::initPolygon(int cell_w, int cell_h, int x_offset, int y_offset ) {
00259 light_border.setPoints(6,
00260 0, 0,
00261 cell_w, 0,
00262 cell_w - x_offset, y_offset,
00263 x_offset, y_offset,
00264 x_offset, cell_h - y_offset,
00265 0, cell_h);
00266
00267 dark_border.setPoints(6,
00268 cell_w, 0,
00269 cell_w, cell_h,
00270 0, cell_h,
00271 x_offset, cell_h - y_offset,
00272 cell_w - x_offset, cell_h - y_offset,
00273 cell_w - x_offset, y_offset);
00274 }
00275
00276 void PiecesTable::paintCell(QPainter *p, int row, int col)
00277 {
00278 int w = cellWidth();
00279 int h = cellHeight();
00280
00281 uint pos = col+row*numCols();
00282
00283
00284 if ( pos >= _map.count() ) {
00285 p->drawRect(0, 0, w, h);
00286 return;
00287 }
00288
00289 int number = _map[col + row * numCols()] + 1;
00290
00291
00292 if(number == numCols()*numRows() ) {
00293 p->setBrush(colorGroup().background());
00294 p->setPen(NoPen);
00295 p->drawRect(0, 0, w, h);
00296 return;
00297 }
00298
00299
00300 if( _pixmap.count() == 0 )
00301 return;
00302
00303 p->drawPixmap(0, 0, *(_pixmap[(number-1 )]) );
00304 }
00305
00306 void PiecesTable::resizeEvent(QResizeEvent *e)
00307 {
00308
00309
00310
00311
00312 if ( e )
00313 QTableView::resizeEvent(e);
00314
00315 setCellWidth(contentsRect().width()/ numCols());
00316 setCellHeight(contentsRect().height() / numRows());
00317
00318
00319
00320 slotCustomImage( _image );
00321
00322 }
00323
00324 void PiecesTable::initColors()
00325 {
00326 _colors.resize(numRows() * numCols());
00327 for (int r = 0; r < numRows(); r++)
00328 for (int c = 0; c < numCols(); c++)
00329 _colors[c + r *numCols()] = QColor( 255 - (70 * c)%255 ,255 - (70 * r)%255, 150);
00330 }
00331
00332 void PiecesTable::initMap()
00333 {
00334 int items = numCols()*numRows();
00335 _map.resize( items );
00336 for ( int i = 0; i < items; i++)
00337 _map[i] = i;
00338
00339 _randomized = false;
00340 }
00341
00342 void PiecesTable::randomizeMap()
00343 {
00344 initMap();
00345 _randomized = true;
00346
00347 int cols = numCols();
00348 int rows = numRows();
00349 int pos = _map.find( cols*rows -1 );
00350
00351 int move = 0;
00352 while ( move < 333 ) {
00353
00354 int frow = pos / cols;
00355 int fcol = pos - frow * cols;
00356
00357
00358 int row = rand()%rows;
00359 int col = rand()%cols;
00360
00361
00362 if ( row < 0 || row >= rows ) continue;
00363 if ( col < 0 || col >= cols ) continue;
00364 if ( row != frow && col != fcol ) continue;
00365
00366 move++;
00367
00368
00369 if(row == frow) {
00370
00371 if (col < fcol) {
00372 for(int c = fcol; c > col; c--) {
00373 _map[c + row * cols] = _map[ c-1 + row *cols];
00374 }
00375 }
00376 else if (col > fcol) {
00377 for(int c = fcol; c < col; c++) {
00378 _map[c + row * cols] = _map[ c+1 + row *cols];
00379 }
00380 }
00381 }
00382
00383 else if (col == fcol) {
00384
00385 if (row < frow) {
00386 for(int r = frow; r > row; r--) {
00387 _map[col + r * cols] = _map[ col + (r-1) *cols];
00388 }
00389 }
00390 else if (row > frow) {
00391 for(int r = frow; r < row; r++) {
00392 _map[col + r * cols] = _map[ col + (r+1) *cols];
00393 }
00394 }
00395 }
00396
00397 _map[pos=(col + row * cols)] = rows*cols-1;
00398 }
00399 repaint();
00400 }
00401
00402 void PiecesTable::checkwin()
00403 {
00404 if(!_randomized) return;
00405
00406 int items=numCols()*numRows();
00407 int i;
00408 for (i = 0; i < items; i++)
00409 if(i != _map[i])
00410 break;
00411
00412 if (i == items) {
00413 QMessageBox::information(this, tr("Fifteen Pieces"),
00414 tr("Congratulations!\nYou win the game!"));
00415 _randomized = FALSE;
00416 }
00417
00418 }
00419
00420 void PiecesTable::slotRandomize()
00421 {
00422 randomizeMap();
00423 }
00424
00425 void PiecesTable::slotReset()
00426 {
00427 initMap();
00428 repaint();
00429 }
00430
00431 void PiecesTable::mousePressEvent(QMouseEvent* e)
00432 {
00433 QTableView::mousePressEvent(e);
00434
00435 if (e->button() == RightButton) {
00436
00437
00438 if(!_menu) {
00439 _menu = new QPopupMenu(this);
00440 _menu->insertItem(tr("R&andomize Pieces"), mRandomize);
00441 _menu->insertItem(tr("&Reset Pieces"), mReset);
00442 _menu->adjustSize();
00443 }
00444
00445
00446 switch(_menu->exec(mapToGlobal(e->pos()))) {
00447 case mRandomize:
00448 randomizeMap();
00449 break;
00450 case mReset:
00451 initMap();
00452 repaint();
00453 break;
00454 default:
00455 break;
00456 }
00457 }
00458 else {
00459
00460 int cols = numCols();
00461 int rows = numRows();
00462 int item = cols*rows -1;
00463
00464
00465 int pos = _map.find(item);
00466 if(pos < 0) return;
00467
00468 int frow = pos / cols;
00469 int fcol = pos - frow * cols;
00470
00471
00472 int row = findRow(e->y());
00473 int col = findCol(e->x());
00474
00475
00476 if (row < 0 || row >= rows) return;
00477 if (col < 0 || col >= cols) return;
00478 if ( row != frow && col != fcol ) return;
00479
00480
00481 if(row != frow && col != fcol) return;
00482
00483
00484 if(row == frow) {
00485
00486 if (col < fcol) {
00487 for(int c = fcol; c > col; c--) {
00488 _map[c + row * cols] = _map[ c-1 + row *cols];
00489 updateCell(row, c, false);
00490 }
00491 }
00492 else if (col > fcol) {
00493 for(int c = fcol; c < col; c++) {
00494 _map[c + row * cols] = _map[ c+1 + row *cols];
00495 updateCell(row, c, false);
00496 }
00497 }
00498 }
00499
00500 else if (col == fcol) {
00501
00502 if (row < frow) {
00503 for(int r = frow; r > row; r--) {
00504 _map[col + r * cols] = _map[ col + (r-1) *cols];
00505 updateCell(r, col, false);
00506 }
00507 }
00508 else if (row > frow) {
00509 for(int r = frow; r < row; r++) {
00510 _map[col + r * cols] = _map[ col + (r+1) *cols];
00511 updateCell(r, col, false);
00512 }
00513 }
00514 }
00515
00516 _map[col + row * cols] = item;
00517 updateCell(row, col, false);
00518
00519
00520 checkwin();
00521 }
00522 }
00523
00524 void PiecesTable::slotConfigure() {
00525 if ( !_dialog )
00526 _dialog = new FifteenConfigDialog(this, "Fifteen Configure Dialog", true );
00527
00528
00529 _dialog->setImageSrc( _image );
00530 _dialog->setGameboard( numRows(), numCols() );
00531
00532 if ( QPEApplication::execDialog(_dialog) == QDialog::Accepted ) {
00533
00534
00535
00536
00537
00538 _image = _dialog->imageSrc();
00539 if (numRows() != _dialog->rows() ||
00540 numCols() != _dialog->columns() ) {
00541 setNumCols(_dialog->columns());
00542 setNumRows(_dialog->rows());
00543 slotReset();
00544 }
00545 resizeEvent( 0l );
00546
00547
00548 update();
00549 }
00550 }