//**************************************************************************** //Copyright (C) 2005-2006 Beijing BlueDJ Technology Co.,Ltd. All rights reserved. //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. //This program is distributed in the hope that it will be useful, //but WITHOUT ANY WARRANTY; without even the implied warranty of //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //GNU General Public License for more details. //You should have received a copy of the GNU General Public License //along with this program (in the file LICENSE.GPL); if not, write to the Free Software //Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. //Please visit http://www.bluedj.com for more infomation about us. //Contact us at ggwizard@gmail.com or darkdong@gmail.com. //****************************************************************************/ #include "DJCanvasView.h" #include "DJGameUser.h" #include "DJGameController.h" #include "DJGamePanel.h" #include "DJCanvasItem.h" static int ZORDER_FOCUS = 90; static int ZORDER_SEAT = 100; static int ZORDER_TABLE = 150; static int ZORDER_AVATAR = 250; static int ZORDER_PLAYING = 300; static int ZORDER_READY = 350; static int ZORDER_NAME = 400; static qreal ZOOM_STEP = 0.2; static qreal MAX_ZOOM = 1.99; static qreal MIN_ZOOM = 0.21; static int CANVASVIEW_MARGIN_Y = 30; DJCell::DJCell( quint8 tableId, const QPixmap& tablePixmap, const QFont& tableFont, const QColor& tableColor, const QList& seatPixmaps, const QPixmap& playingPixmap, DJCanvasView* canvasView ) : m_gamePanel(0),m_canvasView(canvasView) { //djDebug() << "DJCell constructor"; m_playingItem = new DJCanvasItem( m_canvasView->canvas(), playingPixmap, DJCanvasItem::Playing ); m_playingItem->setZ( ZORDER_PLAYING ); m_tableItem = new DJCanvasTable( tablePixmap, tableId, tableFont, m_canvasView->canvas() ); m_tableItem->setPen( tableColor ); m_tableItem->setZ( ZORDER_TABLE ); for ( quint8 seatId = 1; seatId <= seatPixmaps.size(); seatId++ ) { DJCanvasItem *seatItem = new DJCanvasItem( canvasView->canvas(), seatPixmaps.at(seatId-1), DJCanvasItem::Seat, tableId << 8 | seatId ); seatItem->setZ( ZORDER_SEAT ); m_seatItems << seatItem; } } DJCell::~DJCell() { //djDebug() << "DJCell destructor"; delete m_tableItem; delete m_playingItem; qDeleteAll( m_seatItems ); deleteGamePanel(); } void DJCell::draw() { if ( m_canvasView->cellOrigins().isEmpty() ) return; quint8 tableIndex = tableId() - 1; int originx = m_canvasView->cellOrigins().at(tableIndex).x(); int originy = m_canvasView->cellOrigins().at(tableIndex).y(); int centerx = m_canvasView->cellSize().width()/2; int centery = m_canvasView->cellSize().height()/2; int x = originx + centerx - m_tableItem->width()/2; int y = originy + centery - m_tableItem->height()/2; m_tableItem->move( x, y ); m_tableItem->show(); x = originx + centerx - m_playingItem->width()/2; y = originy + centery - m_playingItem->height()/2; m_playingItem->move( x, y ); for ( quint8 seatIndex = 0; seatIndex < numberOfSeats(); seatIndex++ ) { DJCanvasItem *seatItem = m_seatItems.at(seatIndex); x = originx + centerx - seatItem->width()/2 + m_canvasView->seatOffsets().at(seatIndex).x(); y = originy + centery - seatItem->height()/2 + m_canvasView->seatOffsets().at(seatIndex).y(); seatItem->move( x, y ); seatItem->show(); } m_canvasView->canvas()->update(); m_canvasView->updateContents(); } void DJCell::synchronize( quint8 tableStatus, const QList& tableMapUsers ) { djDebug() << "synchronize" ; //set table status setStatus( tableStatus ); //remove user who not in tableMapUsers QList::iterator it1 = m_orderedUsers.begin(); while ( it1 != m_orderedUsers.end() ) { DJGameUser* user = *it1; djDebug() << "m_orderedUsers id = " << user->userId(); if ( !tableMapUsers.contains( user ) ) { djDebug() << "remove user who not in tableMapUsers" << user->userName(); it1 = m_orderedUsers.erase( it1 ); //m_canvasView->requestUserInfo( user->userId() ); //just set user status to idle? user->setTrinity( 0, 0, GAME_STATUS_IDLE ); }else ++it1; } //add user who not in m_orderedUsers QList::const_iterator it2 = tableMapUsers.begin(); while ( it2 != tableMapUsers.end() ) { DJGameUser* user = *it2; djDebug() << "tableMapUsers id = " << user->userId(); if ( !m_orderedUsers.contains( user ) ) { djDebug() << "add user who not in m_orderedUsers" << user->userName(); m_orderedUsers << user; } ++it2; } draw(); } bool DJCell::isPlaying() const { return m_playingItem->isVisible(); } bool DJCell::isIdle() const { return !m_playingItem->isVisible(); } quint8 DJCell::tableId() const { return m_tableItem->id(); } quint8 DJCell::numberOfSeats() const { return m_seatItems.size(); } void DJCell::addUser( DJGameUser* user ) { if ( !m_orderedUsers.contains( user ) ) m_orderedUsers << user; } void DJCell::removeUser( DJGameUser* user ) { int index = m_orderedUsers.indexOf( user ); if ( -1 != index ) { m_orderedUsers.removeAt( index ); } } DJGameUser* DJCell::userAtSeat( quint8 seatId ) { foreach( DJGameUser* user, m_orderedUsers ) { if ( seatId == user->seatId() ) { return user; } } return 0; } void DJCell::setStatus( quint8 tableStatus ) { if ( DJGAME_TABLE_STATUS_IDLE == tableStatus ) m_playingItem->hide(); else { m_playingItem->show(); foreach( DJGameUser* user, m_orderedUsers ) { if ( !user->isPlaying() ) { user->setTrinity( user->tableId(), user->seatId(), GAME_STATUS_PLAYING ); } } } } void DJCell::setGamePanel( DJGamePanel* gamePanel ) { deleteGamePanel(); m_gamePanel = gamePanel; } void DJCell::deleteGamePanel() { if ( m_gamePanel ) { m_gamePanel->closeChildDialog(); m_gamePanel->removePendingAcl(); m_gamePanel->deleteLater(); m_gamePanel = 0; } } QList DJCell::panelUserIds() { //NOTE:userIds = numberOfSeats + 1 ,userIds[0] is always selfid QList userIds; int i; for ( i = 0; i <= numberOfSeats(); i++ ) { userIds << 0; } userIds[0] = m_canvasView->gameController()->selfUserId(); foreach( DJGameUser* user, m_orderedUsers ) { quint8 seat = user->seatId(); if ( seat ) userIds[seat] = user->userId(); } return userIds; } /* QList DJCell::playingSeatIds() { QList seatIds; foreach( DJGameUser* user, m_orderedUsers ) { if ( user->isPlaying() ) seatIds << user->seatId(); } return seatIds; } */ bool DJCell::precede( quint32 firstUserId, quint32 secondUserId ) { djDebug() << "DJCell::precede" << firstUserId << secondUserId; int firstIndex = -1; int secondIndex = -1; for( int i = 0; i < m_orderedUsers.size(); i++ ) { DJGameUser* user = m_orderedUsers.at(i); djDebug() << "userid = " << user->userId() << user->userName(); if ( firstUserId == user->userId() ) firstIndex = i; else if ( secondUserId == user->userId() ) secondIndex = i; } if ( -1 == firstIndex || -1 == secondIndex ) { return false; }else { return firstIndex < secondIndex; } } void DJCell::description() const { djDebug() << "m_orderedUsers size = " << m_orderedUsers.size(); foreach( DJGameUser* user, m_orderedUsers ) { djDebug() << user->userId() << user->userName() << user->tableId() << user->seatId() << user->gameStatus(); } } //--------------------------------------------------------------------------------- DJPlayer::DJPlayer( DJGameUser* user, const QPixmap& readyPixmap, const QFont& nameFont, const QColor& nameColor, DJCanvasView* canvasView ) :m_user(user),m_canvasView(canvasView) { djDebug() << "DJPlayer constructor"; QPixmap avatarPixmap = user->avatar(); m_avatarItem = new DJCanvasAvatar( avatarPixmap, user, readyPixmap, m_canvasView->canvas() ); m_avatarItem->setZ( ZORDER_AVATAR ); m_nameItem = new DJCanvasText( user->userName(), m_canvasView->canvas() ); m_nameItem->setFont( nameFont ); m_nameItem->setColor( nameColor ); m_nameItem->setZ( ZORDER_NAME ); } DJPlayer::~DJPlayer() { djDebug() << "DJPlayer destructor"; delete m_avatarItem; delete m_nameItem; } void DJPlayer::draw() { if ( m_canvasView->cellOrigins().isEmpty() ) return; djDebug() << "DJPlayer::draw" << m_user->userName() << m_user->tableId() << m_user->seatId() << m_user->gameStatus(); DJCanvasItem* selfReadyItem = m_canvasView->selfReadyItem(); quint8 tableId = m_user->tableId(); quint8 seatId = m_user->seatId(); if ( 0 == tableId || 0 == seatId ) { //hide player m_avatarItem->hide(); m_nameItem->hide(); if ( m_user->isSelf() ) { selfReadyItem->hide(); m_canvasView->setFocusTable( 0, false ); } }else { //show player quint8 tableIndex = tableId - 1; quint8 seatIndex = seatId - 1; int originx = m_canvasView->cellOrigins().at(tableIndex).x(); int originy = m_canvasView->cellOrigins().at(tableIndex).y(); int centerx = m_canvasView->cellSize().width()/2; int centery = m_canvasView->cellSize().height()/2; int x = originx + centerx - m_avatarItem->width()/2 + m_canvasView->avatarOffsets().at( seatIndex ).x(); int y = originy + centery - m_avatarItem->height()/2 + m_canvasView->avatarOffsets().at( seatIndex ).y(); m_avatarItem->move( x, y ); m_avatarItem->show(); QRect rect = m_nameItem->boundingRect(); m_nameItem->move( x, y - rect.height() ); m_nameItem->show(); if ( m_user->isSelf() ) { if ( m_user->isDown() ) { x = originx + centerx - selfReadyItem->width()/2; y = originy + centery - selfReadyItem->height()/2; selfReadyItem->move( x, y ); selfReadyItem->show(); }else { selfReadyItem->hide(); } m_canvasView->setFocusTable( m_user->tableId(), false ); } } m_canvasView->canvas()->update(); m_canvasView->updateContents(); } void DJPlayer::reload() { QSize oldSize = m_avatarItem->pixmap().size(); QPixmap avatarPixmap = m_user->avatar(); avatarPixmap = avatarPixmap.scaled( oldSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ); m_avatarItem->setPixmap( avatarPixmap ); m_nameItem->setText( m_user->userName() ); } //--------------------------------------------------------------------------------- static const char* KEY_GAME_CANVASVIEW_SCALE = "GameCanvasViewScale"; DJCanvasView::DJCanvasView( DJGameController* gameController, QWidget* parent ) :Q3CanvasView(parent),m_gameController(gameController) { djDebug("DJCanvasView constructor"); m_selfReadyItem = 0; m_focusRectItem = 0; Q3Canvas* canvas = new Q3Canvas( this ); //canvas->setUpdatePeriod( 500 ); //canvas->setAdvancePeriod( 500 ); setCanvas( canvas ); canvas->setBackgroundPixmap( QPixmap( m_gameController->gameResDir() + "/image/base/floor.png" ) ); setHScrollBarMode(Q3ScrollView::AlwaysOff); setVScrollBarMode(Q3ScrollView::AlwaysOn); m_canvasContextMenu = new QMenu( this ); m_actZoomIn = new QAction( tr("Zoom in"), this ); m_actZoomIn->setShortcut( QKeySequence(Qt::Key_Plus) ); new QShortcut(QKeySequence(Qt::Key_Plus),this,SLOT(zoomIn())); connect( m_actZoomIn, SIGNAL(triggered()), SLOT(zoomIn())); m_canvasContextMenu->addAction(m_actZoomIn); m_actRevert = new QAction( tr("Revert"), this ); connect( m_actRevert, SIGNAL(triggered()), SLOT(revert())); m_canvasContextMenu->addAction(m_actRevert); m_actZoomOut = new QAction( tr("Zoom out"), this ); m_actZoomOut->setShortcut( QKeySequence(Qt::Key_Minus) ); new QShortcut(QKeySequence(Qt::Key_Minus),this,SLOT(zoomOut())); connect( m_actZoomOut, SIGNAL(triggered()), SLOT(zoomOut())); m_canvasContextMenu->addAction(m_actZoomOut); } DJCanvasView::~DJCanvasView() { //all items on canvas should have been deleted djDebug() << "DJCanvasView destructor" << canvas()->allItems().size(); clearAllItems(); } void DJCanvasView::clearAllItems() { djDebug() << "DJCanvasView::clearAllItems"; qDeleteAll( m_cells ); m_cells.clear(); qDeleteAll( m_players ); m_players.clear(); delete m_selfReadyItem; m_selfReadyItem = 0; delete m_focusRectItem ; m_focusRectItem = 0; } DJCell* DJCanvasView::cell( quint8 tableIndex ) const { return m_cells.at( tableIndex ); } QList DJCanvasView::allPanels() const { QList panels; foreach( DJCell* cell, m_cells ) { DJGamePanel *panel = cell->gamePanel(); if ( panel ) { panels << panel; } } return panels; } QList DJCanvasView::allPanelTables() const { QList tableIds; foreach( DJCell* cell, m_cells ) { if ( cell->gamePanel() ) { tableIds << cell->tableId(); } } return tableIds; } void DJCanvasView::initialize( quint8 numberOfTables, const QPixmap& tablePixmap, const QFont& tableFont, const QColor& tableColor, const QList& seatPixmaps, const QPixmap& selfReadyPixmap, const QPixmap& playingPixmap, const QSize& cellSize, const QList& seatOffsets, const QList& avatarOffsets ) { djDebug() << "initialize begin" << numberOfTables; clearAllItems(); m_cellOrigins.clear(); m_cellSize = cellSize; m_seatOffsets = seatOffsets; m_avatarOffsets = avatarOffsets; for ( quint8 tableId = 1; tableId <= numberOfTables; tableId++ ) { DJCell *cell = new DJCell( tableId, tablePixmap, tableFont, tableColor, seatPixmaps, playingPixmap, this ); m_cells << cell; } m_selfReadyItem = new DJCanvasItem( canvas(), selfReadyPixmap, DJCanvasItem::Ready ); m_selfReadyItem->setZ( ZORDER_READY ); m_focusRectItem = new Q3CanvasRectangle( canvas() ); m_focusRectItem->setPen( QPen(Qt::green) ); m_focusRectItem->setSize( m_cellSize.width(), m_cellSize.height() ); m_focusRectItem->setZ( ZORDER_FOCUS ); m_focusRectItem->hide(); QSettings settings; settings.beginGroup( m_gameController->gameName() ); qreal scale = settings.value( KEY_GAME_CANVASVIEW_SCALE, 1 ).toDouble(); settings.endGroup(); QMatrix m; if ( scale != m.m11() ) { m.setMatrix( scale, m.m12(), m.m21(), scale, m.dx(), m.dy() ); setWorldMatrix( m ); emit viewScaleChanged( scale ); } resizeEvent( 0 ); djDebug() << "initialize end"; } void DJCanvasView::addUser( DJGameUser* user, const QPixmap& readyPixmap, const QFont& nameFont, const QColor& nameColor ) { if ( m_players.contains( user ) ) return; DJPlayer *player = new DJPlayer( user, readyPixmap, nameFont, nameColor, this ); m_players.insert( user, player ); connect( user, SIGNAL(trinityChanged(DJGameUser*,quint8,quint8,quint8)), player, SLOT(draw()) ); connect( user, SIGNAL(trinityChanged(DJGameUser*,quint8,quint8,quint8)),SLOT(changeContents(DJGameUser*,quint8,quint8,quint8)) ); connect( user, SIGNAL(reloaded(DJGameUser*)), SLOT(reloadUser(DJGameUser*)) ); djDebug() << "adduser"; changeContents( user, 0, 0, GAME_STATUS_IDLE ); player->draw(); djDebug() << "adduser end"; } void DJCanvasView::reloadUser( DJGameUser* user ) { djDebug() << "DJCanvasView::reloadUser" << user->userName(); if ( !m_players.contains( user ) ) return; DJPlayer *player = m_players.value( user ); player->reload(); player->draw(); } void DJCanvasView::removeUser( DJGameUser* user ) { if ( !m_players.contains( user ) ) return; user->setTrinity( 0, 0, GAME_STATUS_IDLE ); DJPlayer *player = m_players.take( user ); delete player; } /* void DJCanvasView::requestTableMap( quint8 minTableId, quint8 maxTableId ) { m_gameController->requestTableMap( minTableId, maxTableId ); } void DJCanvasView::requestUserInfo( quint32 userId ) { m_gameController->requestUserInfo( userId ); } */ void DJCanvasView::resizeEvent( QResizeEvent * event ) { djDebug() << "DJCanvasView::resizeEvent" << visibleWidth() << visibleHeight() << width() << height(); if ( event )//system call Q3CanvasView::resizeEvent(event); int width = static_cast( visibleWidth() * inverseWorldMatrix().m11() ); //int height = visibleHeight(); if ( m_cells.isEmpty() ) { return; } int intervalx; int intervaly = 20; if ( width <= 0 || visibleHeight() <= 0 ) return; int columns = width / m_cellSize.width(); int space = width % m_cellSize.width(); if ( 0 == columns ) { columns = 1; intervalx = 0; }else { intervalx = space / columns; } int rows = ( m_cells.size() + columns - 1) / columns; djDebug("columns=%d,rows=%d",columns,rows); int height = (m_cellSize.height() + intervaly) * rows + CANVASVIEW_MARGIN_Y; if ( height * worldMatrix().m11() < visibleHeight() ) { height = static_cast(visibleHeight() * inverseWorldMatrix().m11()); } djDebug()<<"canvas resize to"<resize( width, height ); int i,j; m_cellOrigins.clear(); int x = intervalx/2; int y = CANVASVIEW_MARGIN_Y; for ( i = 0; i < rows; i++ ) { for ( j = 0; j < columns; j++ ) { m_cellOrigins << QPoint( x, y ); x += m_cellSize.width() + intervalx; } x = intervalx/2; y += m_cellSize.height() + intervaly; } foreach( DJCell *cell, m_cells ) { cell->draw(); } foreach( DJPlayer *player, m_players ) { player->draw(); } } void DJCanvasView::contentsMousePressEvent( QMouseEvent * e ) { //djDebug("DJCanvasView::contentsMousePressEvent x = %d,y = %d",e->x(),e->y()); Q3CanvasView::contentsMousePressEvent(e); QPoint point = inverseWorldMatrix().map( e->pos() ); Q3CanvasItemList list = canvas()->collisions( point ); for( Q3CanvasItemList::Iterator it = list.begin(); it != list.end(); ++it ) { if ( DJCanvasItem::RTTI != (*it)->rtti() ) continue; DJCanvasItem *item = static_cast(*it); //djDebug() << "type = " << item->type(); switch ( item->type() ) { case DJCanvasItem::Table: if ( item->hit( point ) ) return; break; case DJCanvasItem::Seat: { if ( Qt::LeftButton == e->button() ) { quint16 seatId = item->id(); //djDebug()<<"click seat id = "<< (seatId>>8) << (seatId&0xff); emit sitDown( seatId>>8, seatId&0xff ); } return; } case DJCanvasItem::Ready: if ( Qt::LeftButton == e->button() ) { emit ready(); } return; case DJCanvasItem::Avatar: { DJCanvasAvatar* avatarItem = static_cast(item); DJGameUser* user = avatarItem->user(); if ( Qt::LeftButton == e->button() ) { if ( user->isSelf() ) { emit standUp(); }else { emit leftClicked( user ); } }else { emit rightClicked( user ); } return; } default: break; } } if ( Qt::RightButton == e->button() ) { popupCanvasContextMenu(); } } void DJCanvasView::contentsMouseDoubleClickEvent( QMouseEvent * e ) { djDebug() << "DJCanvasView::contentsMouseDoubleClickEvent"; Q3CanvasView::contentsMouseDoubleClickEvent(e); QPoint point = inverseWorldMatrix().map( e->pos() ); Q3CanvasItemList list = canvas()->collisions( point ); for( Q3CanvasItemList::Iterator it = list.begin(); it != list.end(); ++it ) { if ( DJCanvasItem::RTTI != (*it)->rtti() ) continue; DJCanvasItem *item = static_cast(*it); djDebug() << "type = " << item->type(); switch ( item->type() ) { case DJCanvasItem::Avatar: { DJCanvasAvatar* avatarItem = static_cast(item); DJGameUser* user = avatarItem->user(); if ( Qt::LeftButton == e->button() ) { emit leftDoubleClicked( user ); } return; } default: break; } } } void DJCanvasView::changeContents( DJGameUser* user, quint8 oldTableId, quint8 oldSeatId, quint8 oldGameStatus ) { djDebug() << m_gameController->gameName() << "changeContents" << user->userName() << oldTableId << oldSeatId << oldGameStatus << "-->" << user->tableId() << user->seatId() << user->gameStatus(); quint8 tableId = user->tableId(); quint8 seatId = user->seatId(); //quint8 gameStatus = user->gameStatus(); DJCell* oldCell = 0; DJCell* newCell = 0; if ( oldTableId ) { oldCell = cell(oldTableId - 1); } if ( tableId ) { newCell = cell(tableId - 1); } if ( oldTableId != tableId || oldSeatId != seatId ) { //table seat changed if ( oldCell ) { oldCell->removeUser( user ); } if ( newCell ) { newCell->addUser( user ); } } djDebug() << "end changeContents"; } void DJCanvasView::zoomIn() { djDebug() << "zoomIn"; QMatrix m = worldMatrix(); qreal scale = m.m11(); djDebug() << "scale =" << scale; if ( scale > MAX_ZOOM ) return; scale += ZOOM_STEP; setScale( scale ); emit viewScaleChanged( scale ); } void DJCanvasView::zoomOut() { djDebug() << "zoomOut"; QMatrix m = worldMatrix(); qreal scale = m.m11(); djDebug() << "scale =" << scale; if ( scale < MIN_ZOOM ) { return; } scale -= ZOOM_STEP; setScale( scale ); emit viewScaleChanged( scale ); } void DJCanvasView::revert() { qreal scale = 1; setScale( scale ); emit viewScaleChanged( scale ); } void DJCanvasView::setScale( qreal scale ) { djDebug() << "setScale" << scale; QMatrix m; m.setMatrix( scale, m.m12(), m.m21(), scale, m.dx(), m.dy() ); setWorldMatrix( m ); resizeEvent( 0 ); QSettings settings; settings.beginGroup( m_gameController->gameName() ); settings.setValue( KEY_GAME_CANVASVIEW_SCALE, scale ); settings.endGroup(); } void DJCanvasView::setFocusTable( quint8 tableId, bool drawRect ) { if ( 0 == tableId ) { m_focusRectItem->hide(); }else { //djDebug()<<"canvas size"<width()<height(); //djDebug()<<"visible size"<move( canvasPoint.x(), canvasPoint.y() ); m_focusRectItem->show(); }else m_focusRectItem->hide(); } canvas()->update(); } void DJCanvasView::popupCanvasContextMenu() { qreal scale = worldMatrix().m11(); m_actZoomIn->setEnabled( !(scale > MAX_ZOOM) ); m_actRevert->setEnabled( !(1 == scale) ); m_actZoomOut->setEnabled( !(scale < MIN_ZOOM) ); m_canvasContextMenu->exec( QCursor::pos() ); } /* void DJCanvasView::contentsMouseMoveEvent ( QMouseEvent * e ) { djDebug() << "DJCanvasView::contentsMouseMoveEvent"; } void DJCanvasView::contentsMouseReleaseEvent( QMouseEvent * e ) { djDebug() << "DJCanvasView::contentsMouseReleaseEvent"; } */