/*************************************************************************** challenge_graph.cpp - description ------------------- begin : Mon Jan 7 2002 copyright : (C) 2003 by Eric Faccer email : e.faccer@qut.edu.au ***************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "challenge_graph.moc" #include "challenge_graph_view.h" #include "challenge_rectangle.h" #include "command.h" #include "definitions.h" /* SIZE is for the size of the challenge square. It could become a class variable */ #define SIZE 8 #define OFFSET 2 #define SPACER SIZE+OFFSET /////////////////////////////////////// // // Challenge_Graph::Constructor // /////////////////////////////////////// Challenge_Graph::Challenge_Graph( TQWidget* parent, const char* name, resource *Rsrc ) : TQVBox(parent, name), myResource(Rsrc) { max_rating = 2600; max_time = 60; seek = FALSE; graph = new TQCanvas( 0, "Challenge_Graph" ); myStatusBar = new TQLabel( this, "Challenge_Graph_Status_Bar" ); myView = new Challenge_Graph_View( *graph, this, "Challenge_Graph_View", 0, myStatusBar ); TQObject::connect(myView, TQ_SIGNAL(leftClick(int)), TQ_SLOT(selectMatch(int))); TQObject::connect(myView, TQ_SIGNAL(rightClick(Challenge_Game*, const TQPoint&)), TQ_SLOT(display_menuSeek(Challenge_Game*, const TQPoint&))); /* Setup Style for myStatusBar */ myStatusBar->setAlignment( TQt::AlignAuto | TQt::AlignVCenter | TQt::SingleLine ); myStatusBar->setFrameStyle( TQFrame::Panel | TQFrame::Sunken ); clear(); menuSeek = new TDEPopupMenu( this ); menuSeek->setCheckable( TRUE ); menuSeek->insertItem( i18n("Seek Matches"), this, TQ_SLOT( menuFunct(int) ), 0, MENU_SEEK ); menuSeek->insertSeparator(); menuSeek->insertItem( i18n("Accept This Match"), this, TQ_SLOT( menuFunct(int) ), 0, MENU_ACCEPT_MATCH ); menuSeek->insertItem( i18n("Tell..."), this, TQ_SLOT( menuFunct(int) ), 0, MENU_TELL ); menuSeek->insertItem( i18n("Assess..."), this, TQ_SLOT( menuFunct(int) ), 0, MENU_ASSESS ); menuSeek->insertItem( i18n("Player Info"), this, TQ_SLOT( menuFunct(int) ), 0, MENU_FINGER ); menuSeek->insertItem( TQIconSet( myResource->LoadIcon( TQString("history"), TDEIcon::Small ) ), i18n("Player History"), this, TQ_SLOT( menuFunct(int) ), 0, MENU_HISTORY ); menuSeek->insertSeparator(); menuSeek->insertItem( i18n("Add to Friends"), this, TQ_SLOT( menuFunct(int) ), 0, MENU_NOTIFY ); menuSeek->insertItem( i18n("Ignore This Player"), this, TQ_SLOT( menuFunct(int) ), 0, MENU_CENSOR ); menuSeek->setItemChecked( MENU_SEEK, FALSE ); } /////////////////////////////////////// // // Challenge_Graph::Destructor // /////////////////////////////////////// Challenge_Graph::~Challenge_Graph() { } /////////////////////////////////////// // // Challenge_Graph::resizeEvent // /////////////////////////////////////// void Challenge_Graph::resizeEvent( TQResizeEvent *e ) { if( e->size() != e->oldSize() ) { TQSize newsize = e->size(); x_size = newsize.width() - 8; y_size = newsize.height() - myStatusBar->height(); graph->resize( x_size, y_size ); createBackground(); } } /////////////////////////////////////// // // Challenge_Graph::add // /////////////////////////////////////// void Challenge_Graph::add(Challenge_Game *seek) { double AdjustedClock = (float)seek->clock() + ( ( (float)seek->increment() / 60.0 ) * 20.0 ); double my_x = (float)x_size / (float)max_time * AdjustedClock; double mag = (float)max_rating / (float)y_size; double my_y = ( max_rating - seek->rating() ) / mag; //bleah //a bit of a hack for the status bar real estate & values larger then MAX if ( seek->rating() < 250) my_y = (max_rating - 250) / mag; else if ( seek->rating() >= max_rating ) my_y = 10; if ( seek->clock() > (max_time-3) ) my_x = x_size/max_time * (max_time-3); int time_control_x = (int)(my_x); int rating_y = (int)(my_y); if ( isEmpty(time_control_x, rating_y) ) drawChallenge(time_control_x, rating_y, seek->rated(), seek); else addTo_Nearest_Neighbour(time_control_x, rating_y, seek->rated(), seek); } /////////////////////////////////////// // // Challenge_Graph::clear // /////////////////////////////////////// void Challenge_Graph::clear() { myView->reset(); graph->update(); } /////////////////////////////////////// // // Challenge_Graph::drawChallenge // /////////////////////////////////////// void Challenge_Graph::drawChallenge(int time_control_x, int rating_y, bool rated, Challenge_Game *challenge) { /* This next peice of unelegant code is fairly unnecessary. It is to keep everything on the screen */ /* It's based on the theory of prophylaxis */ int my_x = time_control_x; int my_y = rating_y; if( my_y >= y_size - SPACER) my_y = y_size - SPACER; if( my_y < SPACER ) my_y = SPACER; if( my_x >= x_size - ( SPACER ) ) my_x = x_size - ( SPACER ); /*Since squares draw from the top left */ if( my_x < SPACER ) my_x = SIZE; TQCanvasPolygonalItem *item = new Challenge_Rectangle(my_x, my_y, SIZE, SIZE, graph, challenge); item->setPen( myResource->COLOR_GraphForeground ); item->move( time_control_x, rating_y ); item->show(); if( rated ) item->setBrush( TQBrush(myResource->COLOR_GraphForeground) ); else item->setBrush( TQBrush(myResource->COLOR_GraphBackground, TQt::SolidPattern) ); item->show(); graph->update(); } /////////////////////////////////////// // // Challenge_Graph::isEmpty // /////////////////////////////////////// bool Challenge_Graph::isEmpty(int x, int y) { TQCanvasItemList l = graph->collisions( TQRect(x, y, SIZE, SIZE) ); if( l.count() ) return false; return true; } /* This function does a spiral search for the nearest neighbour */ /* Pre: TRUE Post: Finds the nearest non-overlapping position to the original coordinates */ /////////////////////////////////////// // // Challenge_Graph::addTo_Nearest_Neighbour // /////////////////////////////////////// bool Challenge_Graph::addTo_Nearest_Neighbour(int orig_x, int orig_y, bool rated, Challenge_Game * challenge, int searchdepth) { int right = 1; int down = 2; int left = 2; int up = 3; int x = orig_x; int y = orig_y - ( SIZE + OFFSET ); /* Check the location on top*/ if ( isEmpty( x, y ) ) { drawChallenge( x, y, rated, challenge ); return true; } /* Now search in a spiral */ while( right < searchdepth ) { for( int i = 0; i < right; i++ ) { x += SPACER; if( isEmpty( x, y ) ) { drawChallenge( x, y, rated, challenge ); return true; } } for( int i = 0; i < down; i++ ) { y += SPACER; if( isEmpty( x, y ) ) { drawChallenge( x, y, rated, challenge ); return true; } } for( int i = 0; i < left; i++ ) { x -= SPACER; if( isEmpty( x, y) ) { drawChallenge( x, y, rated, challenge ); return true; } } for( int i = 0; i < up; i++ ) { y -= SPACER; if( isEmpty( x, y ) ) { drawChallenge( x, y, rated, challenge ); return true; } } /* Grow the spiral bounds */ right += 2; down += 2; left += 2; up += 2; } return false; } /////////////////////////////////////// // // Challenge_Graph::createBackground // /////////////////////////////////////// void Challenge_Graph::createBackground( void ) { TQPainter painter; TQColor ink; TQWMatrix matrix; int colorTotal; background.resize( y_size, x_size ); background.fill( myResource->COLOR_GraphBackground ); /* Find out if we have a dark bgcolor or a light one. */ colorTotal = ( myResource->COLOR_GraphBackground.red() + myResource->COLOR_GraphBackground.blue() + myResource->COLOR_GraphBackground.green() ); /* Set our ink to something that will contrast well */ if( colorTotal < 384 ) // 384 = 50% gray ink = myResource->COLOR_GraphBackground.light(); else ink = myResource->COLOR_GraphBackground.dark(); /* Paint the text on */ painter.begin( &background ); painter.setFont( myResource->FONT_Standard ); painter.setPen( ink ); painter.drawText( 64, 12, i18n( "Rating" ) ); painter.end(); matrix.rotate( -90.0 ); background = background.xForm( matrix ); painter.begin( &background ); painter.setFont( myResource->FONT_Standard ); painter.setPen( ink ); painter.drawText( 64, y_size - 8, i18n( "Time" ) ); painter.end(); graph->setBackgroundPixmap( background ); } /////////////////////////////////////// // // Challenge_Graph::selectMatch // /////////////////////////////////////// void Challenge_Graph::selectMatch( int matchID ) { if( matchID ) emit sendCMD( Command( 0, CMD_Start_Match, TQString::number( matchID ) ) ); } /////////////////////////////////////// // // Challenge_Graph::menuFunct // /////////////////////////////////////// void Challenge_Graph::menuFunct( int funct ) { switch( funct ) { case MENU_SEEK: emit sendCMD( Command( 0, CMD_Toggle_Seek ) ); break; case MENU_FINGER: emit sendCMD( Command( 0, CMD_Player_Finger, selectedPlayerName ) ); break; case MENU_TELL: emit sendCMD( Command( 0, CMD_Set_Input, TQString( "tell %1 " ).arg( selectedPlayerName ) ) ); break; case MENU_NOTIFY: emit sendCMD( Command( 0, CMD_Add_Friend, selectedPlayerName ) ); break; case MENU_CENSOR: emit sendCMD( Command( 0, CMD_Ignore_Player, selectedPlayerName ) ); break; case MENU_HISTORY: emit sendCMD( Command( 0, CMD_Player_History, selectedPlayerName ) ); break; case MENU_ACCEPT_MATCH: emit sendCMD( Command( 0, CMD_Start_Match, TQString::number( selectedMatchID ) ) ); break; case MENU_ASSESS: emit sendCMD( Command( 0, CMD_Assess, selectedPlayerName ) ); break; default: break; } } /////////////////////////////////////// // // Challenge_Graph::updateSoughtList // /////////////////////////////////////// void Challenge_Graph::updateSoughtList( void ) { unsigned int loop; Challenge_Game *cg; clear(); for( loop = 0; loop < SF_01.count(); loop++ ) { cg = new Challenge_Game( SF_01[loop], SF_02[loop], SF_03[loop], SF_04[loop], SF_05[loop], SF_06[loop], SF_07[loop] ); add( cg ); } SF_01.clear(); SF_02.clear(); SF_03.clear(); SF_04.clear(); SF_05.clear(); SF_06.clear(); SF_07.clear(); seek = TRUE; } /////////////////////////////////////// // // Challenge_Graph::addSoughtItem // /////////////////////////////////////// void Challenge_Graph::addSoughtItem( const TQString &src ) { TQStringList fields = TQStringList::split( TQChar(' '), src, FALSE ); SF_01 << fields[2]; // Name SF_02 << fields[1]; // Rating SF_03 << fields[6]; // Match Type SF_04 << fields[5]; // Is Rated? SF_05 << fields[3]; // Base Time SF_06 << fields[4]; // Increment SF_07 << fields[0]; // ID# } /////////////////////////////////////// // // Challenge_Graph::display_menuSeek // /////////////////////////////////////// void Challenge_Graph::display_menuSeek( Challenge_Game *Item, const TQPoint &Pos ) { bool enable; if( Item != NULL ) { selectedPlayerName = Item->_player.replace( TQRegExp("\\(.+\\)"), TQString("") ); selectedMatchID = Item->id(); enable = TRUE; } else { enable = FALSE; } menuSeek->setItemChecked( MENU_SEEK, seek ); menuSeek->setItemEnabled( MENU_FINGER, enable ); menuSeek->setItemEnabled( MENU_TELL, enable ); menuSeek->setItemEnabled( MENU_NOTIFY, enable ); menuSeek->setItemEnabled( MENU_CENSOR, enable ); menuSeek->setItemEnabled( MENU_HISTORY, enable ); menuSeek->setItemEnabled( MENU_ACCEPT_MATCH, enable ); menuSeek->setItemEnabled( MENU_ASSESS, enable ); menuSeek->popup( Pos ); } /////////////////////////////////////// // // Challenge_Graph::recvCMD // /////////////////////////////////////// void Challenge_Graph::recvCMD( const Command& command ) { switch(((Command)command).getCommand()) { case CMD_Add_Sought_Match: addSoughtItem( ((Command)command).getData() ); break; case CMD_Show_Sought_List: updateSoughtList(); break; case CMD_Hide_Sought_List: clear(); seek = FALSE; break; default: break; } }