You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
knights/knights/challenge_graph.cpp

461 lines
13 KiB

/***************************************************************************
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 <tdepopupmenu.h>
#include <tqapplication.h>
#include <tqcanvas.h>
#include <tqlabel.h>
#include <tqpen.h>
#include <tqscrollview.h>
#include <tqwidget.h>
#include <tqrect.h>
#include <tqbrush.h>
#include <tqpainter.h>
#include <tqregexp.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( 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;
}
}