/* Implementation of class BoardWidget * * This class handles rendering of a Board to a KDE/QT widget, * shows moves (with a timer) and manages input of moves * * Josef Weidendorfer, 9/97 */ #include #include #include #include #include #ifdef HAVE_KIR #include #endif #include "Board.h" #include "BoardWidget.h" /* Cursors */ #include "bitmaps/Arrow1" #include "bitmaps/Arrow1Mask" #include "bitmaps/Arrow2" #include "bitmaps/Arrow2Mask" #include "bitmaps/Arrow3" #include "bitmaps/Arrow3Mask" #include "bitmaps/Arrow4" #include "bitmaps/Arrow4Mask" #include "bitmaps/Arrow5" #include "bitmaps/Arrow5Mask" #include "bitmaps/Arrow6" #include "bitmaps/Arrow6Mask" BoardWidget::BoardWidget(Board& b, TQWidget *parent, const char *name) : BallWidget(10,9,parent, name), board(b) { pList =0; gettingMove = false; editMode = false; renderMode = false; #ifdef HAVE_KIR m_backRenderer = KIRManager::attach( this, "Background" ); connect( m_backRenderer, TQT_SIGNAL(rendered()), this, TQT_SLOT(drawBoard()) ); #endif /* setup cursors */ #define createCursor(bitmap,name) \ static TQBitmap bitmap(bitmap##_width, bitmap##_height, \ (unsigned char *) bitmap##_bits, TRUE); \ static TQBitmap bitmap##Mask(bitmap##Mask_width, bitmap##Mask_height, \ (unsigned char *) bitmap##Mask_bits, TRUE); \ name = new TQCursor(bitmap, bitmap##Mask, bitmap##_x_hot, bitmap##_y_hot); createCursor(Arrow1, arrow[1]); createCursor(Arrow2, arrow[2]); createCursor(Arrow3, arrow[3]); createCursor(Arrow4, arrow[4]); createCursor(Arrow5, arrow[5]); createCursor(Arrow6, arrow[6]); setCursor(crossCursor); // boardColor = new TQColor("lightblue"); boardColor = new TQColor(backgroundColor()); redColor = new TQColor("red2"); yellowColor = new TQColor("yellow2"); redHColor = new TQColor("orange"); yellowHColor = new TQColor("green"); initBalls(); updatePosition(); } BoardWidget::~BoardWidget() { for(int i=1; i<7; i++) if (arrow[i] != 0) delete arrow[i]; #ifdef HAVE_KIR if (m_backRenderer != 0) delete m_backRenderer; #endif delete boardColor; delete redColor; delete yellowColor; delete redHColor; delete yellowHColor; } void BoardWidget::configure() { #ifdef HAVE_KIR if (m_backRenderer != 0) { m_backRenderer->setup(); m_backRenderer->manager()->saveModules(); } #endif } void BoardWidget::createPos(int pos, int i, int j, Ball* b) { int x=(465*(2*(i)-(j))/9); int y=(500*19*(j)/100); createBallPosition(pos, x,y, b); } void BoardWidget::initBalls() { n2 = new Ball( *yellowColor ); h2 = new Ball( *yellowHColor ); d2 = new Ball( *yellowHColor, 3.14/2 ); n1 = new Ball( *redColor ); h1 = new Ball( *redHColor ); d1 = new Ball( *redHColor, 3.14/2 ); // e = new Ball( white,0,0 ); // e->setSpecials(.6,.85,.75); createBlending(1,10,h1,n1); createBlending(2,10,h1,d1); createBlending(3,10,h2,n2); createBlending(4,10,h2,d2); int i,j,pos; for(j=-4;j<5;j++) for(i= ((j>0)?j-4:-4) ; i< ((j<0)?5+j:5) ;i++) { pos=60+j*11+i; createPos(pos, i,j, 0); } pos = 0; /* the outer marks of color1 */ for(i=0;i<3;i++) createPos(pos++, -6, i-4, 0 ); for(i=0;i<3;i++) createPos(pos++, 2+i, i-4, 0 ); /* the outer marks of color2 */ for(i=0;i<3;i++) createPos(pos++, 6, 4-i, 0 ); for(i=0;i<3;i++) createPos(pos++, -2-i, 4-i, 0 ); } void BoardWidget::resizeEvent(TQResizeEvent *e) { drawBoard(); BallWidget::resizeEvent(e); } void BoardWidget::moveEvent(TQMoveEvent*) { drawBoard(); } void BoardWidget::paintEvent(TQPaintEvent *) { if (renderMode) { pm = boardPM; BallWidget::paint(TQT_TQPAINTDEVICE(&pm)); } else draw(); bitBlt(this, 0, 0, &pm); } void drawShadedHexagon(TQPainter *p, int x, int y, int r, int lineWidth, const TQColorGroup& g, bool sunken) { int dx=r/2, dy=(r*87)/100; int y1=y-dy, y2=y+dy; int i; TQPen oldPen = p->pen(); p->setPen(sunken ? g.midlight() : g.dark()); for(i=0; idrawLine( x-i+dx, y-dy, x+2*dx-i, y); p->drawLine( x+2*dx-i, y, x-i+dx, y+dy); p->drawLine( x-i+dx, y1+i, x+i-dx, y1+i); } p->setPen(sunken ? g.dark() : g.midlight()); for(i=0; idrawLine( x+i-dx, y-dy, x+i-2*dx, y); p->drawLine( x+i-2*dx, y, x+i-dx, y+dy); p->drawLine( x-i+dx, y2-i, x+i-dx, y2-i); } p->setPen(oldPen); } void drawColor(TQPainter *p, int x, int y, int r, TQColor* c) { TQColor w("white"); TQPalette pal(*c); TQPen oldPen = p->pen(); TQBrush oldBrush = p->brush(); p->setBrush(pal.active().dark()); p->setPen(pal.active().dark()); p->drawEllipse( x-r - 10,y-r +5, 2*r,2*r); p->setBrush(pal.active().mid()); p->setPen(pal.active().mid()); p->drawEllipse( x-r,y-r, 2*r,2*r); p->setBrush(pal.active().light()); p->setPen(pal.active().light()); p->drawEllipse( x-r/3, y-r/3, 4*r/3,4*r/3); p->setBrush(w); p->setPen(w); p->drawEllipse( x+r/3, y+r/3, r/3,r/3); p->setPen(oldPen); p->setBrush(oldBrush); } void BoardWidget::drawBoard() { boardPM.resize(width(), height()); boardPM.fill(this, 0,0); #ifndef HAVE_KIR TQColorGroup g = TQPalette( *boardColor ).active(); TQColorGroup g2 = TQWidget::colorGroup(); int boardSize = width() *10/12; if (boardSize > height()) boardSize = height(); TQPainter p; p.begin(&boardPM); p.setBrush(g2.brush(TQColorGroup::Mid)); TQWMatrix m; TQPoint cp = rect().center(); m.translate(cp.x(), cp.y()); m.scale(boardSize/1100.0, boardSize/1000.0); m.rotate(0); p.setWorldMatrix(m); /* draw field */ int i,j; TQPointArray a; int dx=520 /2, dy=(520 *87)/100; a.setPoints(6, -dx,-dy, dx,-dy, 2*dx,0, dx,dy, -dx,dy, -2*dx,0 ); p.drawPolygon(a); drawShadedHexagon(&p, 0,0, 505, 1, g, false); drawShadedHexagon(&p, 0,0, 512, 3, g, true); drawShadedHexagon(&p, 0,0, 525, 5, g2, true); #define xpos(i,j) (495*(2*(i)-(j))/9) #define ypos(j) (500*19*(j)/100) for(j=-4;j<5;j++) for(i= ((j>0)?j-4:-4) ; i< ((j<0)?5+j:5) ;i++) { int x=xpos(i,j); int y=ypos(j); drawShadedHexagon(&p, x,y, 50, 2, g, true); drawShadedHexagon(&p, x,y, 30, 1, g, false); } p.end(); #endif draw(); } void BoardWidget::renderBalls(bool r) { renderMode=r; draw(); } void BoardWidget::updateBalls() { int i,j; for(j=-4;j<5;j++) for(i= ((j>0)?j-4:-4) ; i< ((j<0)?5+j:5) ;i++) { int pos = 60+j*11+i; int w=field[60+j*11+i]; if (w==Board::color1) { if (positions[pos]->def != n1) { positions[pos]->def= n1; startAnimation(pos,1, ANIMATION_FORWARD); } else { stopAnimation(pos); } } else if (w==Board::color1bright) startAnimation(pos,2,ANIMATION_LOOP); else if (w==Board::color2) { if (positions[pos]->def != n2) { positions[pos]->def= n2; startAnimation(pos,3,ANIMATION_FORWARD); } else { stopAnimation(pos); } } else if (w==Board::color2bright) startAnimation(pos,4,ANIMATION_LOOP); else if (w==Board::free) { positions[pos]->def= 0; positions[pos]->actAnimation = 0; // stopAnimation(pos); } } for(i=0;i<6;i++) positions[i]->def= ((14-color1Count)>i && color1Count>0) ? n1:0; for(i=6;i<12;i++) positions[i]->def= ((14-color2Count)>i-6 && color2Count>0) ? n2:0; } void BoardWidget::draw() { if (boardPM.isNull()) return; pm = boardPM; if (renderMode) { updateBalls(); repaint(false); return; } int boardSize = width() *10/12; if (boardSize > height()) boardSize = height(); TQPainter p; p.begin(&pm); p.setBrush(foregroundColor()); TQWMatrix m; TQPoint cp = rect().center(); m.translate(cp.x(), cp.y()); m.scale(boardSize/1100.0, boardSize/1000.0); m.rotate(0); p.setWorldMatrix(m); /* draw fields */ int i,j; for(j=-4;j<5;j++) for(i= ((j>0)?j-4:-4) ; i< ((j<0)?5+j:5) ;i++) { int x=xpos(i,j); int y=ypos(j); int w=field[60+j*11+i]; if (w==Board::color1) drawColor(&p, x,y, 35, redColor ); else if (w==Board::color1bright) drawColor(&p, x,y, 35, redHColor ); else if (w==Board::color2) drawColor(&p, x,y, 35, yellowColor ); else if (w==Board::color2bright) drawColor(&p, x,y, 35, yellowHColor ); } if (color1Count >0) { /* the outer marks of color1 */ if (color1Count <12) { for(i=11; i>8 && i>color1Count ;i--) drawColor(&p, xpos(12-i,7-i)+55, ypos(7-i), 35, redColor ); } for(i=14; i>11 && i>color1Count ;i--) drawColor(&p, xpos(-6,10-i)+55, ypos(10-i), 35, redColor ); /* the outer marks of color2 */ if (color2Count <12) { for(i=11; i>8 && i>color2Count ;i--) drawColor(&p, xpos(i-12,i-7)-55, ypos(i-7), 35, yellowColor); } for(i=14; i>11 && i>color2Count ;i--) drawColor(&p, xpos(6,i-10)-55, ypos(i-10), 35, yellowColor); } p.end(); bitBlt(this, 0, 0, &pm); } /** updatePosition * * Update my position with that of the member. * If is true, draw widget */ void BoardWidget::updatePosition(bool updateGUI) { for(int i=0; i2) ? Board::color1bright:Board::free; opponentNew = (step<2) ? Board::color2 : Board::color2bright; } else { colorNew = (step<2) ? Board::color2 : (step>2) ? Board::color2bright:Board::free; opponentNew = (step<2) ? Board::color1 : Board::color1bright; } afterMove = (step == 1) || (step == 4); f = m.field; dir = Board::fieldDiffOfDir(m.direction); /* first field */ field[f] = afterMove ? Board::free : colorNew; switch(m.type) { case Move::out2: /* (c c c o o |) */ field[f + dir] = colorNew; field[f + 2*dir] = colorNew; field[f + 3*dir] = afterMove ? colorNew : opponentNew; field[f + 4*dir] = opponentNew; break; case Move::out1with3: /* (c c c o |) */ field[f + dir] = colorNew; field[f + 2*dir] = colorNew; field[f + 3*dir] = afterMove ? colorNew : opponentNew; break; case Move::move3: /* (c c c .) */ field[f + dir] = colorNew; field[f + 2*dir] = colorNew; field[f + 3*dir] = afterMove ? colorNew : Board::free; break; case Move::out1with2: /* (c c o |) */ field[f + dir] = colorNew; field[f + 2*dir] = afterMove ? colorNew : opponentNew; break; case Move::move2: /* (c c .) */ field[f + dir] = colorNew; field[f + 2*dir] = afterMove ? colorNew : Board::free; break; case Move::push2: /* (c c c o o .) */ field[f + dir] = colorNew; field[f + 2*dir] = colorNew; field[f + 3*dir] = afterMove ? colorNew : opponentNew; field[f + 4*dir] = opponentNew; field[f + 5*dir] = afterMove ? opponentNew : Board::free; break; case Move::left3: dir2 = Board::fieldDiffOfDir(m.direction-1); field[f+dir2] = afterMove ? colorNew : Board::free; field[f+=dir] = afterMove ? Board::free : colorNew; field[f+dir2] = afterMove ? colorNew : Board::free; field[f+=dir] = afterMove ? Board::free : colorNew; field[f+dir2] = afterMove ? colorNew : Board::free; break; case Move::right3: dir2 = Board::fieldDiffOfDir(m.direction+1); field[f+dir2] = afterMove ? colorNew : Board::free; field[f+=dir] = afterMove ? Board::free : colorNew; field[f+dir2] = afterMove ? colorNew : Board::free; field[f+=dir] = afterMove ? Board::free : colorNew; field[f+dir2] = afterMove ? colorNew : Board::free; break; case Move::push1with3: /* (c c c o .) => (. c c c o) */ field[f + dir] = colorNew; field[f + 2*dir] = colorNew; field[f + 3*dir] = afterMove ? colorNew : opponentNew; field[f + 4*dir] = afterMove ? opponentNew : Board::free; break; case Move::push1with2: /* (c c o .) => (. c c o) */ field[f + dir] = colorNew; field[f + 2*dir] = afterMove ? colorNew : opponentNew; field[f + 3*dir] = afterMove ? opponentNew : Board::free; break; case Move::left2: dir2 = Board::fieldDiffOfDir(m.direction-1); field[f+dir2] = afterMove ? colorNew : Board::free; field[f+=dir] = afterMove ? Board::free : colorNew; field[f+dir2] = afterMove ? colorNew : Board::free; break; case Move::right2: dir2 = Board::fieldDiffOfDir(m.direction+1); field[f+dir2] = afterMove ? colorNew : Board::free; field[f+=dir] = afterMove ? Board::free : colorNew; field[f+dir2] = afterMove ? colorNew : Board::free; break; case Move::move1: /* (c .) => (. c) */ field[f + dir] = afterMove ? colorNew : Board::free; break; default: break; } if (updateGUI) draw(); } void BoardWidget::showStart(const Move& m, int step, bool updateGUI) { int f, dir; int colorNew; if (boardOK) { /* board ok means: board has the normal state before move */ if (step == 0) return; /* nothing to be done */ } boardOK = (step == 0) ? true:false; if (color == Board::color1) colorNew = (step==0) ? Board::color1 : Board::color1bright; else colorNew = (step==0) ? Board::color2 : Board::color2bright; f = m.field; /* first field */ field[f] = colorNew; switch(m.type) { case Move::left3: case Move::right3: dir = Board::fieldDiffOfDir(m.direction); field[f + dir] = colorNew; field[f + 2*dir] = colorNew; break; case Move::left2: case Move::right2: dir = Board::fieldDiffOfDir(m.direction); field[f + dir] = colorNew; default: break; } if (updateGUI) draw(); } void BoardWidget::choseMove(MoveList *pl) { if (!gettingMove && pl != 0) { pList = pl; gettingMove = true; mbDown = false; actValue = - board.calcEvaluation(); kdDebug(12011) << "Chose Move..." << endl; } } /* returns position of point (xx,yy) */ int BoardWidget::positionOf(int xx, int yy) { int boardSize = TQMIN( width()*10/12, height() ); int x = (1000 * (xx- (width()-boardSize)/2)) / boardSize; int y = (1000 * (yy- (height()-boardSize)/2)) / boardSize; /* kdDebug(12011) << "(" << xx << "," << yy << ") -> (" << x << "," << y << ")" << endl; */ y = (y-2)/47; if (y < 2 || y > 18) return 0; x= ((x+25)/25+ (y-10) )/2; if (y < 10 && ((x < 2) || (x > 8+y) )) return 0; if (y >= 10 && ((x < y-8) || (x > 18) )) return 0; return 22*y + x; } bool isBetweenFields(int pos) { bool res = ( ((pos%2) == 1) || ( ((pos/22)%2) == 1) ); // kdDebug(12011) << "Pos " << pos << " is between fields: " << res << endl; return res; } int fieldOf(int pos) { int f = 11*(pos/44) + (pos%22)/2; // kdDebug(12011) << "Field1 of pos " << pos << " is " << f << endl; return f; } int field2Of(int pos) { int y = pos/22, x = pos%22; int f2 = 0, f1 = 11*(y/2) + (x/2); if ( (y%2) == 0) { /* exact on row */ if ( (x%2) != 0) { /* horizontial between fields */ f2 = f1+1; } } else { /* vertical between fields */ f2 = f1 + ( ((x%2)==0) ? 11:12 ); } // kdDebug(12011) << "Field2 of pos " << pos << " is " << f2 << endl; return f2; } /* get direction depending on difference of positions */ int directionOfPosDiff(int d) { if (d>0) { return ((d<21) ? Move::Right : ((d%22) == 0) ? Move::LeftDown : ((d%23) == 0) ? Move::RightDown : 0); } else if (d<0) { return ((d>-21) ? Move::Left : ((d%23) == 0) ? Move::LeftUp : ((d%22) == 0) ? Move::RightUp : 0); } return 0; } int directionOfFieldDiff(int d) { if (d>0) { return ((d<10) ? Move::Right : ((d%11) == 0) ? Move::LeftDown : ((d%12) == 0) ? Move::RightDown : 0); } else if (d<0) { return ((d>-10) ? Move::Left : ((d%12) == 0) ? Move::LeftUp : ((d%11) == 0) ? Move::RightUp : 0); } return 0; } /* Check if is a valid start position for a allowed move * If yes, set * , and */ bool BoardWidget::isValidStart(int pos, bool midPressed) { bool res = false; int f1 = fieldOf(pos); startField = f1; if (isBetweenFields(pos)) { int f2 = field2Of(pos); actMove = Move(f1, directionOfFieldDiff( f2-f1 ), Move::none); res = pList->isElement(actMove, MoveList::start2); if (!res) { startField = f2; actMove = Move(f2, directionOfFieldDiff( f1-f2 ), Move::none); res = pList->isElement(actMove, MoveList::start2); } startType = MoveList::start2; return res; } if (midPressed) { startType = MoveList::start3; /* Check all 6 directions */ for(int dir=1;dir<7;dir++) { actMove = Move(f1 - Board::fieldDiffOfDir(dir), dir, Move::none ); if (pList->isElement(actMove, startType)) return true; } /* if we don't find a side move3 fall trough to normal moves... */ } startType = MoveList::start1; actMove = Move(f1, 0, Move::none); res = pList->isElement(actMove, startType); return res; } /* Check if is a valid end position for a move * regarding * If yes, set */ bool BoardWidget::isValidEnd(int pos) { int dir = directionOfPosDiff(pos - startPos); Move m; if (dir == 0) return false; switch(startType) { case MoveList::start1: m = Move(startField, dir, Move::none); if (!pList->isElement(m, startType)) return false; break; case MoveList::start2: { int f1 = fieldOf(startPos); int f2 = field2Of(startPos); int dir2 = directionOfFieldDiff( f2-f1 ); int dir3 = directionOfFieldDiff( f1-f2 ); switch((dir2-dir+6)%6) { case 1: m = Move(f1, dir2, Move::left2); break; case 2: m = Move(f2, dir3, Move::right2); break; case 4: m = Move(f2, dir3, Move::left2); break; case 5: m = Move(f1, dir2, Move::right2); break; default: return false; } if (!pList->isElement(m, startType)) return false; break; } case MoveList::start3: { int rightDir = (dir%6)+1; m = Move( startField - Board::fieldDiffOfDir(rightDir), rightDir, Move::left3 ); if (!pList->isElement(m, startType)) { int leftDir = ((dir-2)%6)+1; m = Move( startField - Board::fieldDiffOfDir(leftDir), leftDir, Move::right3 ); if (!pList->isElement(m, startType)) return false; } } break; } actMove = m; shownDirection = dir; return true; } void BoardWidget::mousePressEvent( TQMouseEvent* pEvent ) { int pos = positionOf( pEvent->x(), pEvent->y() ); int f = fieldOf(pos); if (pEvent->button() == Qt::RightButton) { emit rightButtonPressed(f, pEvent->globalPos()); return; } if (!gettingMove && !editMode) { return; } mbDown = true; if (editMode) { editColor = (pEvent->button() == Qt::MidButton) ? Board::color2 : Board::color1; int newColor = (pEvent->button() == Qt::MidButton) ? Board::color2bright : Board::color1bright; if (field[f] == Board::free) { field[f] = newColor; } else if (field[f] == Board::color1) { if (editColor == Board::color1) { editColor = Board::free; newColor = Board::color1bright; } field[f] = newColor; } else if (field[f] == Board::color2) { if (editColor == Board::color2) { editColor = Board::free; newColor = Board::color2bright; } field[f] = newColor; } else { editColor = Board::out; } oldPos = pos; draw(); return; } startValid = isValidStart(pos, (pEvent->button() == Qt::MidButton)); kdDebug(12011) << "Start pos " << pos << " is valid: " << startValid << endl; // actMove.print(); if (!startValid) return; startPos = oldPos = pos; showStart(actMove,1); startShown = true; TQString tmp; actValue = - board.calcEvaluation(); tmp = i18n("Board value: %1").arg(actValue); emit updateSpy(tmp); } void BoardWidget::mouseMoveEvent( TQMouseEvent* pEvent ) { if ((!gettingMove && !editMode) || !mbDown) return; int pos = positionOf( pEvent->x(), pEvent->y() ); if (pos == oldPos) return; oldPos = pos; if (editMode) { int f = fieldOf(pos); if (field[f] != Board::out && field[f] != editColor) { int newColor = (editColor == Board::color1) ? Board::color1bright : (editColor == Board::color2) ? Board::color2bright : (field[f] == Board::color1) ? Board::color1bright : (field[f] == Board::color2) ? Board::color2bright : field[f]; field[f] = newColor; draw(); } return; } if (!startValid) { /* We haven't a valid move yet. Check if we are over a valid start */ startValid = isValidStart(pos, (pEvent->button() == Qt::MidButton)); kdDebug(12011) << "Start pos " << pos << " is valid: " << startValid << endl; // actMove.print(); if (!startValid) return; startPos = oldPos = pos; showStart(actMove,1); startShown = true; TQString tmp; actValue = - board.calcEvaluation(); tmp = i18n("Board value: %1").arg(actValue); emit updateSpy(tmp); return; } /* restore board */ updatePosition(); startShown = false; if (isValidEnd(pos)) { // actMove.print(); board.playMove(actMove); int v = board.calcEvaluation(); board.takeBack(); TQString tmp; tmp.sprintf("%+d", v-actValue); TQString str = TQString("%1 : %2").arg(actMove.name()).arg(tmp); emit updateSpy(str); showMove(actMove,3); setCursor(*arrow[shownDirection]); } else { TQString tmp; setCursor(crossCursor); if (pos == startPos) { showStart(actMove,1); startShown = true; tmp = i18n("Board value: %1").arg(actValue); } else draw(); emit updateSpy(tmp); } } void BoardWidget::mouseReleaseEvent( TQMouseEvent* pEvent ) { if (!gettingMove && !editMode) return; mbDown = false; if (editMode) { int i; // printf("Releasing..."); for(i=0; ix(), pEvent->y() ); if (isValidEnd(pos)) { // actMove.print(); startValid = false; setCursor(crossCursor); gettingMove = false; emit moveChoosen(actMove); return; } updatePosition(true); startValid = false; setCursor(crossCursor); TQString tmp; emit updateSpy(tmp); } TQSize BoardWidget::sizeHint() const { return TQSize(400, 350); } #include "BoardWidget.moc"