00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "Editor.h"
00021
00022 #include <QLabel>
00023 #include <qevent.h>
00024 #include <qpainter.h>
00025
00026 #include "prefs.h"
00027
00028 #include <kmessagebox.h>
00029 #include <kcomponentdata.h>
00030 #include <klocale.h>
00031 #include <kstandarddirs.h>
00032 #include <kaction.h>
00033 #include <kactioncollection.h>
00034 #include <ktoggleaction.h>
00035 #include <kstandardaction.h>
00036 #include <kicon.h>
00037
00038
00039
00040
00041
00042
00043 Editor::Editor ( QWidget* parent)
00044 : KDialog( parent ), tiles()
00045 {
00046 setModal(true);
00047 clean= true;
00048 numTiles=0;
00049 mode = insert;
00050
00051 QString tile = Prefs::tileSet();
00052 if (!tiles.loadTileset(tile)) tiles.loadDefault();
00053
00054
00055 int sWidth = ( theBoard.m_width+2)*(tiles.qWidth());
00056 int sHeight =( theBoard.m_height+2)*tiles.qHeight();
00057
00058 sWidth += 4*tiles.levelOffsetX();
00059
00060 drawFrame = new FrameImage( this, QSize(sWidth, sHeight) );
00061 drawFrame->setGeometry( 10, 40 ,sWidth ,sHeight);
00062 drawFrame->setMinimumSize( 0, 0 );
00063 drawFrame->setMaximumSize( 32767, 32767 );
00064 drawFrame->setFocusPolicy( Qt::NoFocus );
00065
00066 drawFrame->setMouseTracking(true);
00067
00068
00069 setupToolbar();
00070
00071 QVBoxLayout *layout = new QVBoxLayout(this);
00072 layout->addWidget(topToolbar,0);
00073 layout->addWidget(drawFrame,1);
00074 layout->activate();
00075
00076 resize( sWidth+60, sHeight+60);
00077
00078 setMinimumHeight(120);
00079
00080
00081 setCaption(i18n("Edit Board Layout"));
00082
00083 connect( drawFrame, SIGNAL(mousePressed(QMouseEvent *) ),
00084 SLOT(drawFrameMousePressEvent(QMouseEvent *)));
00085 connect( drawFrame, SIGNAL(mouseMoved(QMouseEvent *) ),
00086 SLOT(drawFrameMouseMovedEvent(QMouseEvent *)));
00087
00088 statusChanged();
00089
00090 update();
00091 }
00092
00093
00094
00095 Editor::~Editor()
00096 {
00097 }
00098
00099 void Editor::resizeEvent ( QResizeEvent * event )
00100 {
00101 QSize newtiles = tiles.preferredTileSize(event->size(), (theBoard.m_width+2)/2,( theBoard.m_height+2)/2);
00102 tiles.reloadTileset(newtiles);
00103 }
00104
00105
00106 void Editor::setupToolbar()
00107 {
00108
00109 topToolbar = new KToolBar( this, "editToolBar" );
00110 topToolbar->setToolButtonStyle( Qt::ToolButtonIconOnly );
00111
00112 actionCollection = new KActionCollection(this);
00113
00114 QAction* newBoard = actionCollection->addAction("new_board");
00115 newBoard->setIcon(KIcon("document-new"));
00116 newBoard->setText(i18n("New board"));
00117 connect(newBoard, SIGNAL(triggered(bool)), SLOT(newBoard()));
00118 topToolbar->addAction(newBoard);
00119
00120 QAction* openBoard = actionCollection->addAction("open_board");
00121 openBoard->setIcon(KIcon("document-open"));
00122 openBoard->setText(i18n("Open board"));
00123 connect(openBoard, SIGNAL(triggered(bool)), SLOT(loadBoard()));
00124 topToolbar->addAction(openBoard);
00125
00126 QAction* saveBoard = actionCollection->addAction("save_board");
00127 saveBoard->setIcon(KIcon("document-save"));
00128 saveBoard->setText(i18n("Save board"));
00129 connect(saveBoard, SIGNAL(triggered(bool)), SLOT(saveBoard()));
00130 topToolbar->addAction(saveBoard);
00131
00132
00133
00134 topToolbar->addSeparator();
00135 #ifdef FUTURE_OPTIONS
00136
00137 QAction* select = actionCollection->addAction("select");
00138 select->setIcon(KIcon("rectangle_select"));
00139 select->setText(i18n("Select"));
00140 topToolbar->addAction(select);
00141
00142
00143 QAction* cut = actionCollection->addAction("edit_cut");
00144 cut->setIcon(KIcon("edit-cut"));
00145 cut->setText(i18n("Cut"));
00146 topToolbar->addAction(cut);
00147
00148 QAction* copy = actionCollection->addAction("edit_copy");
00149 copy->setIcon(KIcon("edit-copy"));
00150 copy->setText(i18n("Copy"));
00151 topToolbar->addAction(copy);
00152
00153 QAction* paste = actionCollection->addAction("edit_paste");
00154 paste->setIcon(KIcon("edit-paste"));
00155 paste->setText(i18n("Paste"));
00156 topToolbar->addAction(paste);
00157
00158 topToolbar->addSeparator();
00159
00160 QAction* moveTiles = actionCollection->addAction("move_tiles");
00161 moveTiles->setIcon(KIcon("move"));
00162 moveTiles->setText(i18n("Move tiles"));
00163 topToolbar->addAction(moveTiles);
00164 #endif
00165 KToggleAction* addTiles = new KToggleAction(KIcon("draw-freehand"), i18n("Add tiles"), this);
00166 actionCollection->addAction("add_tiles", addTiles);
00167 topToolbar->addAction(addTiles);
00168 KToggleAction* delTiles = new KToggleAction(KIcon("edit-delete"), i18n("Remove tiles"), this);
00169 actionCollection->addAction("del_tiles", delTiles);
00170 topToolbar->addAction(delTiles);
00171
00172 QActionGroup* radioGrp = new QActionGroup(this);
00173 radioGrp->setExclusive(true);
00174 radioGrp->addAction(addTiles);
00175 addTiles->setChecked(true);
00176 #ifdef FUTURE_OPTIONS
00177 radioGrp->addAction(moveTiles);
00178 #endif
00179 radioGrp->addAction(delTiles);
00180 connect(radioGrp, SIGNAL(triggered(QAction*)), SLOT(slotModeChanged(QAction*)));
00181
00182
00183
00184 topToolbar->addSeparator();
00185
00186
00187
00188 QAction* shiftLeft = actionCollection->addAction("shift_left");
00189 shiftLeft->setIcon(KIcon("go-previous"));
00190 shiftLeft->setText(i18n("Shift left"));
00191 connect(shiftLeft, SIGNAL(triggered(bool)), SLOT(slotShiftLeft()));
00192 topToolbar->addAction(shiftLeft);
00193
00194 QAction* shiftUp = actionCollection->addAction("shift_up");
00195 shiftUp->setIcon(KIcon("go-up"));
00196 shiftUp->setText(i18n("Shift up"));
00197 connect(shiftUp, SIGNAL(triggered(bool)), SLOT(slotShiftUp()));
00198 topToolbar->addAction(shiftUp);
00199
00200 QAction* shiftDown = actionCollection->addAction("shift_down");
00201 shiftDown->setIcon(KIcon("go-down"));
00202 shiftDown->setText(i18n("Shift down"));
00203 connect(shiftDown, SIGNAL(triggered(bool)), SLOT(slotShiftDown()));
00204 topToolbar->addAction(shiftDown);
00205
00206 QAction* shiftRight = actionCollection->addAction("shift_right");
00207 shiftRight->setIcon(KIcon("go-next"));
00208 shiftRight->setText(i18n("Shift right"));
00209 connect(shiftRight, SIGNAL(triggered(bool)), SLOT(slotShiftRight()));
00210 topToolbar->addAction(shiftRight);
00211
00212 topToolbar->addSeparator();
00213 QAction* quit = actionCollection->addAction(KStandardAction::Quit, "quit",
00214 this, SLOT(close()));
00215 topToolbar->addAction(quit);
00216
00217
00218
00219 QWidget *hbox = new QWidget(topToolbar);
00220 QHBoxLayout *layout = new QHBoxLayout(hbox);
00221 layout->setMargin(0);
00222 layout->setSpacing(0);
00223 layout->addStretch();
00224
00225 theLabel = new QLabel(statusText(), hbox);
00226 layout->addWidget(theLabel);
00227 topToolbar->addWidget(hbox);
00228
00229 topToolbar->adjustSize();
00230 setMinimumWidth(topToolbar->width());
00231 }
00232
00233 void Editor::statusChanged() {
00234 bool canSave = ((numTiles !=0) && ((numTiles & 1) == 0));
00235 theLabel->setText(statusText());
00236 actionCollection->action("save_board")->setEnabled(canSave);
00237 }
00238
00239 void Editor::slotShiftLeft()
00240 {
00241 theBoard.shiftLeft();
00242 update();
00243 }
00244
00245 void Editor::slotShiftRight()
00246 {
00247 theBoard.shiftRight();
00248 update();
00249 }
00250
00251 void Editor::slotShiftUp()
00252 {
00253 theBoard.shiftUp();
00254 update();
00255 }
00256
00257 void Editor::slotShiftDown()
00258 {
00259 theBoard.shiftDown();
00260 update();
00261 }
00262
00263 void Editor::slotModeChanged(QAction* act)
00264 {
00265 if(act == actionCollection->action("move_tiles"))
00266 {
00267 mode = move;
00268 }
00269 else if(act == actionCollection->action("del_tiles"))
00270 {
00271 mode = remove;
00272 }
00273 else if(act == actionCollection->action("add_tiles"))
00274 {
00275 mode = insert;
00276 }
00277 }
00278
00279 QString Editor::statusText() {
00280 QString buf;
00281
00282 int x=currPos.x;
00283 int y=currPos.y;
00284 int z= currPos.e;
00285
00286 if (z == 100)
00287 z = 0;
00288 else
00289 z=z+1;
00290
00291 if (x >= theBoard.m_width || x <0 || y >=theBoard.m_height || y <0)
00292 x = y = z = 0;
00293
00294 buf = i18n("Tiles: %1 Pos: %2,%3,%4", numTiles, x, y, z);
00295 return buf;
00296 }
00297
00298
00299 void Editor::loadBoard() {
00300
00301 if ( !testSave() )
00302 return;
00303
00304 KUrl url = KFileDialog::getOpenUrl(
00305 KUrl(),
00306 i18n("*.layout|Board Layout (*.layout)\n"
00307 "*|All Files"),
00308 this,
00309 i18n("Open Board Layout" ));
00310
00311 if ( url.isEmpty() )
00312 return;
00313
00314
00315 theBoard.loadBoardLayout( url.path() );
00316 update();
00317 }
00318
00319
00320
00321
00322 void Editor::newBoard() {
00323 if (!testSave())
00324 return;
00325
00326 theBoard.clearBoardLayout();
00327
00328 clean=true;
00329 numTiles=0;
00330 statusChanged();
00331 update();
00332 }
00333
00334 bool Editor::saveBoard() {
00335
00336 KUrl url = KFileDialog::getSaveUrl(
00337 KUrl(),
00338 i18n("*.layout|Board Layout (*.layout)\n"
00339 "*|All Files"),
00340 this,
00341 i18n("Save Board Layout" ));
00342
00343 if ( url.isEmpty() )
00344 return false;
00345
00346 if( !url.isLocalFile() )
00347 {
00348 KMessageBox::sorry( this, i18n( "Only saving to local files currently supported." ) );
00349 return false;
00350 }
00351
00352
00353 QFileInfo f( url.path() );
00354 if ( f.exists() ) {
00355
00356 int res=KMessageBox::warningContinueCancel(this,
00357 i18n("A file with that name "
00358 "already exists. Do you "
00359 "wish to overwrite it?"),
00360 i18n("Save Board Layout" ), KStandardGuiItem::save());
00361 if (res != KMessageBox::Continue)
00362 return false;
00363 }
00364
00365 bool result = theBoard.saveBoardLayout( url.path() );
00366 if (result==true){
00367 clean = true;
00368 return true;
00369 } else {
00370 return false;
00371 }
00372 }
00373
00374
00375
00376 bool Editor::testSave()
00377 {
00378
00379 if (clean)
00380 return(true);
00381
00382 int res;
00383 res=KMessageBox::warningYesNoCancel(this,
00384 i18n("The board has been modified. Would you "
00385 "like to save the changes?"), QString(), KStandardGuiItem::save(),KStandardGuiItem::dontSave());
00386
00387 if (res == KMessageBox::Yes) {
00388
00389 if (saveBoard()) {
00390 return true;
00391 } else {
00392 KMessageBox::sorry(this, i18n("Save failed. Aborting operation."));
00393 }
00394 } else {
00395 return (res != KMessageBox::Cancel);
00396 }
00397 return(true);
00398 }
00399
00400
00401
00402
00403
00404 void Editor::paintEvent( QPaintEvent* ) {
00405
00406 QPixmap buff;
00407 QPixmap *dest=drawFrame->getPreviewPixmap();
00408 buff = QPixmap(dest->width(), dest->height());
00409 drawBackground(&buff);
00410 drawTiles(&buff);
00411 QPainter p(dest);
00412 p.drawPixmap(0,0, buff);
00413 p.end();
00414
00415 drawFrame->update();
00416 }
00417
00418 void Editor::drawBackground(QPixmap *pixmap) {
00419
00420 QPainter p(pixmap);
00421
00422
00423 p.fillRect(0,0,pixmap->width(), pixmap->height(), Qt::white);
00424
00425
00426
00427 int sy = (tiles.height()/2)+tiles.levelOffsetX();
00428 int sx = (tiles.width()/2);
00429
00430 for (int y=0; y<=theBoard.m_height; y++) {
00431 int nextY=sy+(y*tiles.qHeight());
00432 p.drawLine(sx, nextY,sx+(theBoard.m_width*tiles.qWidth()), nextY);
00433 }
00434
00435 for (int x=0; x<=theBoard.m_width; x++) {
00436 int nextX=sx+(x*tiles.qWidth());
00437 p.drawLine(nextX, sy, nextX, sy+theBoard.m_height*tiles.qHeight());
00438 }
00439 }
00440
00441 void Editor::drawTiles(QPixmap *dest) {
00442
00443 QPainter p(dest);
00444
00445 int xOffset = tiles.width()/2;
00446 int yOffset = tiles.height()/2;
00447 short tile = 0;
00448
00449
00450
00451
00452 for (int z=0; z< theBoard.m_depth; z++) {
00453
00454 for (int y = 0; y < theBoard.m_height; y++) {
00455
00456 for (int x= theBoard.m_width-1; x>=0; x--) {
00457 int sx = x*(tiles.qWidth() )+xOffset;
00458 int sy = y*(tiles.qHeight() )+yOffset;
00459 if (theBoard.getBoardData(z, y, x) != '1') {
00460 continue;
00461 }
00462 QPixmap t;
00463 tile=(z*theBoard.m_depth)+
00464 (y*theBoard.m_height)+
00465 (x*theBoard.m_width);
00466
00467
00468
00469 t = tiles.unselectedTile(0);
00470
00471
00472
00473
00474
00475
00476
00477
00478 if ((x>1) && (y>0) && theBoard.getBoardData(z,y-1,x-2)=='1'){
00479 p.drawPixmap( sx+tiles.levelOffsetX(), sy,
00480 t, tiles.levelOffsetX() ,0,
00481 t.width()-tiles.levelOffsetX(),
00482 t.height()/2);
00483
00484
00485 p.drawPixmap( sx, sy+t.height()/2,
00486 t, 0,t.height()/2,t.width(),t.height()/2);
00487 } else {
00488
00489 p.drawPixmap(sx, sy,
00490 t, 0,0, t.width(), t.height());
00491 }
00492
00493
00494 tile++;
00495 tile = tile % 143;
00496 }
00497 }
00498 xOffset +=tiles.levelOffsetX();
00499 yOffset -=tiles.levelOffsetY();
00500 }
00501 }
00502
00503
00504
00505
00506
00507
00508 void Editor::transformPointToPosition(
00509 const QPoint& point,
00510 POSITION& MouseClickPos,
00511 bool align)
00512 {
00513
00514 short z = 0;
00515 short y = 0;
00516 short x = 0;
00517 MouseClickPos.e = 100;
00518
00519
00520 for( z=theBoard.m_depth-1; z>=0; z-- )
00521 {
00522
00523
00524
00525 x = ((point.x()-tiles.width()/2)-(z+1)*tiles.levelOffsetX())/ tiles.qWidth();
00526 y = ((point.y()-tiles.height()/2)+ z*tiles.levelOffsetX()) / tiles.qHeight();
00527
00528
00529
00530 if (x<0 || x>=theBoard.m_width || y<0 || y>=theBoard.m_height)
00531 continue;
00532
00533
00534 switch( theBoard.getBoardData(z,y,x) )
00535 {
00536 case (UCHAR)'3': if (align) {
00537 x--;
00538 y--;
00539 }
00540 break;
00541
00542 case (UCHAR)'2': if (align)
00543 x--;
00544 break;
00545
00546 case (UCHAR)'4': if (align)
00547 y--;
00548 break;
00549
00550 case (UCHAR)'1': break;
00551
00552 default : continue;
00553 }
00554
00555 if ( ! theBoard.getBoardData(z,y,x) )
00556 continue;
00557
00558
00559 MouseClickPos.e = z;
00560 MouseClickPos.y = y;
00561 MouseClickPos.x = x;
00562 MouseClickPos.f = theBoard.getBoardData(z,y,x);
00563 break;
00564 }
00565 if (MouseClickPos.e == 100) {
00566 MouseClickPos.x = x;
00567 MouseClickPos.y = y;
00568 MouseClickPos.f=0;
00569 }
00570 }
00571
00572
00573
00574 void Editor::drawFrameMousePressEvent( QMouseEvent* e )
00575 {
00576
00577 POSITION mPos;
00578 transformPointToPosition(e->pos(), mPos, (mode == remove));
00579
00580 switch (mode) {
00581 case remove:
00582 if (!theBoard.tileAbove(mPos) && mPos.e < theBoard.m_depth && theBoard.isTileAt(mPos) ) {
00583 theBoard.deleteTile(mPos);
00584 numTiles--;
00585 statusChanged();
00586 drawFrameMouseMovedEvent(e);
00587 update();
00588 }
00589 break;
00590 case insert: {
00591 POSITION n = mPos;
00592 if (n.e == 100)
00593 n.e = 0;
00594 else
00595 n.e += 1;
00596 if (canInsert(n)) {
00597 theBoard.insertTile(n);
00598 numTiles++;
00599 statusChanged();
00600 update();
00601 }
00602 }
00603 break;
00604 default:
00605 break;
00606 }
00607
00608 }
00609
00610
00611 void Editor::drawCursor(POSITION &p, bool visible)
00612 {
00613 int x = (tiles.width()/2)+(p.e*tiles.levelOffsetX())+(p.x * tiles.qWidth());
00614 int y = (tiles.height()/2)-(p.e*tiles.levelOffsetX())+(p.y * tiles.qHeight());
00615 int w = tiles.width();
00616 int h = tiles.height();
00617
00618
00619 if (p.e==100 || !visible)
00620 x = -1;
00621 drawFrame->setRect(x,y,w,h, tiles.levelOffsetX(), mode-remove);
00622 drawFrame->update();
00623 }
00624
00625
00626
00627
00628 void Editor::drawFrameMouseMovedEvent( QMouseEvent* e ){
00629
00630 POSITION mPos;
00631 transformPointToPosition(e->pos(), mPos, (mode == remove));
00632
00633 if ((mPos.x==currPos.x) && (mPos.y==currPos.y) && (mPos.e==currPos.e))
00634 return;
00635 currPos = mPos;
00636
00637 statusChanged();
00638
00639 switch(mode) {
00640 case insert: {
00641 POSITION next;
00642 next = currPos;
00643 if (next.e == 100)
00644 next.e = 0;
00645 else
00646 next.e += 1;
00647
00648 drawCursor(next, canInsert(next));
00649 break;
00650 }
00651 case remove:
00652 drawCursor(currPos, 1);
00653 break;
00654
00655 case move:
00656
00657 break;
00658
00659 }
00660 }
00661
00662
00663
00664
00665
00666 bool Editor::canInsert(POSITION &p) {
00667
00668
00669 if (p.e >= theBoard.m_depth)
00670 return (false);
00671 if (p.y >theBoard.m_height-2)
00672 return false;
00673 if (p.x >theBoard.m_width-2)
00674 return false;
00675
00676 POSITION n = p;
00677 if (p.e != 0) {
00678 n.e -= 1;
00679 if (!theBoard.allFilled(n)) {
00680 return(false);
00681 }
00682 }
00683 int any = theBoard.anyFilled(p);
00684 return(!any);
00685
00686 }
00687
00688
00689
00690 #include "Editor.moc"