summaryrefslogtreecommitdiffstats
path: root/knights/challenge_graph.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'knights/challenge_graph.cpp')
-rw-r--r--knights/challenge_graph.cpp460
1 files changed, 460 insertions, 0 deletions
diff --git a/knights/challenge_graph.cpp b/knights/challenge_graph.cpp
new file mode 100644
index 0000000..5d36ff1
--- /dev/null
+++ b/knights/challenge_graph.cpp
@@ -0,0 +1,460 @@
+/***************************************************************************
+ 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 <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <kiconloader.h>
+#include <kstddirs.h>
+#include <kpopupmenu.h>
+
+#include <qapplication.h>
+#include <qcanvas.h>
+#include <qlabel.h>
+#include <qpen.h>
+#include <qscrollview.h>
+#include <qwidget.h>
+#include <qrect.h>
+#include <qbrush.h>
+#include <qpainter.h>
+#include <qregexp.h>
+
+#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( QWidget* parent, const char* name, resource *Rsrc )
+ : QVBox(parent, name), myResource(Rsrc)
+{
+ max_rating = 2600;
+ max_time = 60;
+ seek = FALSE;
+
+ graph = new QCanvas( 0, "Challenge_Graph" );
+ myStatusBar = new QLabel( this, "Challenge_Graph_Status_Bar" );
+ myView = new Challenge_Graph_View( *graph, this, "Challenge_Graph_View", 0, myStatusBar );
+
+ QObject::connect(myView, SIGNAL(leftClick(int)), SLOT(selectMatch(int)));
+ QObject::connect(myView, SIGNAL(rightClick(Challenge_Game*, const QPoint&)), SLOT(display_menuSeek(Challenge_Game*, const QPoint&)));
+
+
+ /* Setup Style for myStatusBar */
+ myStatusBar->setAlignment( Qt::AlignAuto | Qt::AlignVCenter | Qt::SingleLine );
+ myStatusBar->setFrameStyle( QFrame::Panel | QFrame::Sunken );
+ clear();
+
+ menuSeek = new KPopupMenu( this );
+ menuSeek->setCheckable( TRUE );
+ menuSeek->insertItem( i18n("Seek Matches"), this, SLOT( menuFunct(int) ), 0, MENU_SEEK );
+ menuSeek->insertSeparator();
+ menuSeek->insertItem( i18n("Accept This Match"), this, SLOT( menuFunct(int) ), 0, MENU_ACCEPT_MATCH );
+ menuSeek->insertItem( i18n("Tell..."), this, SLOT( menuFunct(int) ), 0, MENU_TELL );
+ menuSeek->insertItem( i18n("Assess..."), this, SLOT( menuFunct(int) ), 0, MENU_ASSESS );
+ menuSeek->insertItem( i18n("Player Info"), this, SLOT( menuFunct(int) ), 0, MENU_FINGER );
+ menuSeek->insertItem( QIconSet( myResource->LoadIcon( QString("history"), KIcon::Small ) ),
+ i18n("Player History"), this, SLOT( menuFunct(int) ), 0, MENU_HISTORY );
+ menuSeek->insertSeparator();
+ menuSeek->insertItem( i18n("Add to Friends"), this, SLOT( menuFunct(int) ), 0, MENU_NOTIFY );
+ menuSeek->insertItem( i18n("Ignore This Player"), this, 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( QResizeEvent *e )
+{
+ if( e->size() != e->oldSize() )
+ {
+ QSize 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;
+
+ QCanvasPolygonalItem *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( QBrush(myResource->COLOR_GraphForeground) );
+ else
+ item->setBrush( QBrush(myResource->COLOR_GraphBackground, Qt::SolidPattern) );
+
+ item->show();
+ graph->update();
+}
+///////////////////////////////////////
+//
+// Challenge_Graph::isEmpty
+//
+///////////////////////////////////////
+bool Challenge_Graph::isEmpty(int x, int y)
+{
+ QCanvasItemList l = graph->collisions( QRect(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 )
+{
+ QPainter painter;
+ QColor ink;
+ QWMatrix 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, QString::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, QString( "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, QString::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 QString &src )
+{
+ QStringList fields = QStringList::split( QChar(' '), 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 QPoint &Pos )
+{
+ bool enable;
+ if( Item != NULL )
+ {
+ selectedPlayerName = Item->_player.replace( QRegExp("\\(.+\\)"), QString("") );
+ 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;
+ }
+}