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.
tdeedu/kalzium/src/periodictableview.cpp

1383 lines
38 KiB

/***************************************************************************
* Copyright (C) 2003-2005 by Carsten Niehaus *
* cniehaus@kde.org *
* *
* 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; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include "periodictableview.h"
#include "prefs.h"
#include "element.h"
#include "kalziumtip.h"
#include "kalziumutils.h"
#include "kalziumdataobject.h"
#include <klocale.h>
#include <kdebug.h>
#include <kpixmapeffect.h>
#include <kimageeffect.h>
#include <tqimage.h>
#include <tqstring.h>
#include <tqtooltip.h>
#include <tqwhatsthis.h>
#include <tqlabel.h>
#include <tqpixmap.h>
#include <tqpoint.h>
#include <tqcursor.h>
#include <tqpainter.h>
#include <tqcolor.h>
#include <tqrect.h>
PerodicTableView::PerodicTableView(TQWidget *parent, const char *name)
: TQWidget(parent, name), m_kalziumTip(0), table(0), table2(0)
{
d = KalziumDataObject::instance();
// No selection
unSelect();
#if 0
connect( this, TQT_SIGNAL( tableClicked( TQPoint ) ),
this, TQT_SLOT( selectPoint( TQPoint ) ) );
#endif
connect( this, TQT_SIGNAL( ToolTip( int ) ),
this, TQT_SLOT( slotToolTip( int ) ) );
connect( &HoverTimer, TQT_SIGNAL( timeout() ),
this, TQT_SLOT( slotTransientLabel() ) );
connect( &MouseoverTimer, TQT_SIGNAL( timeout() ),
this, TQT_SLOT( slotMouseover() ) );
setMouseTracking( true );
//JH: eliminates flicker on redraw
setBackgroundMode( TQWidget::NoBackground );
m_molcalcIsActive = false;
m_showTooltip = true;
m_showLegend = Prefs::showlegend();
m_showLegendTooltip = Prefs::tooltip();
m_timeline = false;
m_showSOM = false;
m_showGradient = false;
m_tooltipsEnabled = Prefs::tooltip();
reloadColours();
//IUPAC
m_IUPAClist.append( "IA");
m_IUPAClist.append( "IIA");
m_IUPAClist.append( "IIIB");
m_IUPAClist.append( "IVB");
m_IUPAClist.append( "VB");
m_IUPAClist.append( "VIB");
m_IUPAClist.append( "VIIB");
m_IUPAClist.append( "VIII");
m_IUPAClist.append( "VIII");
m_IUPAClist.append( "VIII");
m_IUPAClist.append( "IB");
m_IUPAClist.append( "IIB");
m_IUPAClist.append( "IIIA");
m_IUPAClist.append( "IVA");
m_IUPAClist.append( "VA");
m_IUPAClist.append( "VIA");
m_IUPAClist.append( "VIIA");
m_IUPAClist.append( "VIIIA");
//oldIUPAC
m_IUPACOLDlist.append( "1A");
m_IUPACOLDlist.append( "2A");
m_IUPACOLDlist.append( "3A");
m_IUPACOLDlist.append( "4A");
m_IUPACOLDlist.append( "5A");
m_IUPACOLDlist.append( "6A");
m_IUPACOLDlist.append( "7A");
m_IUPACOLDlist.append( "8");
m_IUPACOLDlist.append( "8");
m_IUPACOLDlist.append( "8");
m_IUPACOLDlist.append( "1B");
m_IUPACOLDlist.append( "2B");
m_IUPACOLDlist.append( "3B");
m_IUPACOLDlist.append( "4B");
m_IUPACOLDlist.append( "5B");
m_IUPACOLDlist.append( "6B");
m_IUPACOLDlist.append( "7B");
m_IUPACOLDlist.append( "0");
table = new TQPixmap();
table2 = new TQPixmap();
m_kalziumTip = new KalziumTip( this );
//JH: Start with a full draw
doFullDraw = true;
// according to carsten :)
setMinimumSize(ELEMENTSIZE*18+1, ELEMENTSIZE*10+30);
}
void PerodicTableView::reloadColours()
{
color_s = Prefs::block_s();
color_p = Prefs::block_p();
color_d = Prefs::block_d();
color_f = Prefs::block_f();
color_1 = Prefs::group_1();
color_2 = Prefs::group_2();
color_3 = Prefs::group_3();
color_4 = Prefs::group_4();
color_5 = Prefs::group_5();
color_6 = Prefs::group_6();
color_7 = Prefs::group_7();
color_8 = Prefs::group_8();
color_ba = Prefs::beh_basic();
color_ac = Prefs::beh_acidic();
color_neu = Prefs::beh_neutral();
color_amp = Prefs::beh_amphoteric();
c_alkalie = Prefs::alkalie();
c_rare = Prefs::rare();
c_nonmetal = Prefs::nonmetal();
c_alkaline = Prefs::alkaline();
c_other_metal = Prefs::other_metal();
c_halogene = Prefs::halogene();
c_transition = Prefs::transition();
c_noble_gas = Prefs::noble_gas();
c_metalloid = Prefs::metalloid();
c_solid = Prefs::color_solid();
c_vapor = Prefs::color_vapor();
c_liquid = Prefs::color_liquid();
}
void PerodicTableView::slotToolTip( int number )
{
if ( !m_showTooltip || !m_tooltipsEnabled )
return; //don't update if the table is locked
m_tooltipElementNumber = number;
TQWidget *p = 0;
if ( dynamic_cast<TQWidget*>( parent() ) )
p = TQT_TQWIDGET( parent() );
if( p )
m_kalziumTip->showTip( mapFromGlobal(TQCursor::pos()),
d->element(number),
p->width(),
p->height() );
}
PerodicTableView::~PerodicTableView(){}
void PerodicTableView::activateColorScheme( const int nr )
{
m_currentScheme = nr;
EList::ConstIterator it = d->ElementList.begin();
const EList::ConstIterator itEnd = d->ElementList.end();
if ( m_currentScheme == PerodicTableView::NOCOLOUR ) //normal view, no colors
{
const TQColor color = Prefs::noscheme();
while ( it != itEnd )
{
( *it )->setElementColor( color );
++it;
}
}
else if ( m_currentScheme == PerodicTableView::GROUPS ) //groups view
{
static TQString group;
while ( it != itEnd )
{
group = ( *it )->group();
if (group == TQString("1")) {
( *it )->setElementColor( color_1 );
}
if (group == TQString("2")){
( *it )->setElementColor( color_2 );
}
if (group == TQString("3")){
( *it )->setElementColor( color_3 );
}
if (group == TQString("4")){
( *it )->setElementColor( color_4 );
}
if (group == TQString("5")){
( *it )->setElementColor( color_5 );
}
if (group == TQString("6")){
( *it )->setElementColor( color_6 );
}
if (group == TQString("7")){
( *it )->setElementColor( color_7 );
}
if (group == TQString("8")){
( *it )->setElementColor( color_8 );
}
++it;
}
}
else if ( m_currentScheme == PerodicTableView::BLOCK ) //block view
{
static TQString block;
while ( it != itEnd )
{
block = (*it)->block();
if (block == TQString("s")) {
(*it)->setElementColor( color_s );
}
if (block == TQString("p")) {
(*it)->setElementColor( color_p );
}
if (block == TQString("d")) {
(*it)->setElementColor( color_d );
}
if (block == TQString("f")) {
(*it)->setElementColor( color_f );
}
++it;
}
}
else if ( m_currentScheme == PerodicTableView::ACIDIC ) //acidic beh
{
static TQString acidicbeh;
while ( it != itEnd )
{
acidicbeh = ( *it )->acidicbeh();
if (acidicbeh == TQString("0")) {
(*it)->setElementColor( color_ac );
}
if (acidicbeh == TQString("1")){
(*it)->setElementColor( color_ba );
}
if (acidicbeh == TQString("2")){
(*it)->setElementColor( color_neu );
}
if (acidicbeh == TQString("3")){
(*it)->setElementColor( color_amp );
}
++it;
}
}
else if ( m_currentScheme == PerodicTableView::FAMILY ) //familiy of the element
{
static TQString family;
while ( it != itEnd )
{
family = ( *it )->family();
if ( family == "Noblegas" ){
(*it)->setElementColor( c_noble_gas );
}
if ( family == "Non-Metal" ){
(*it)->setElementColor( c_nonmetal );
}
if ( family == "Rare_Earth" ){
(*it)->setElementColor( c_rare );
}
if ( family == "Alkaline_Earth" ){
(*it)->setElementColor( c_alkaline );
}
if ( family == "Alkali_Earth" ){
(*it)->setElementColor( c_alkalie );
}
if ( family == "Transition" ){
(*it)->setElementColor( c_transition );
}
if ( family == "Other_Metal" ){
(*it)->setElementColor( c_other_metal );
}
if ( family == "Metalloids" ){
(*it)->setElementColor( c_metalloid );
}
if ( family == "Halogene" ){
(*it)->setElementColor( c_halogene );
}
++it;
}
}
}
void PerodicTableView::resizeEvent( TQResizeEvent * /*e*/ )
{
table->resize( width(), height() );
table2->resize( width(), height() );
// XXX: I know it isn't the best way, but otherwise the table won't be redrawn
// on repaint... Feel *free* to remove these two lines if you foind a better
// solution...
doFullDraw = true;
update();
}
void PerodicTableView::paintEvent( TQPaintEvent * /*e*/ )
{
TQPainter p;
//JH: I have split the drawing into two pixmaps: table and table2.
//table contains the "static" PerodicTableView table, and does not change very often.
//table2 contains the tooltips and any other dynamic overlays.
//Usually, we can skip the code which renders the table, and just use the
//image stored in table...when doFullDraw==false, the rendering code is skipped.
if ( doFullDraw )
{
//DEBUG
kdDebug() << "Drawing full table" << endl;
p.begin( table );
p.fillRect( 0, 0, width(), height(), paletteBackgroundColor() );
// Draw the numbers above the table.
drawNumeration( &p );
drawLegend( &p );
if ( m_timeline )
{ //use timeline
drawTimeLine(& p );
p.end();
*table2 = *table;
bitBlt( this, 0, 0, table2 );
return;
}
if ( som() )
{//use state of matter
drawSOMPerodicTableView(& p );
p.end();
*table2 = *table;
bitBlt( this, 0, 0, table2 );
return;
}
if ( gradient() )
{//show a gradient
calculateGradient(& p );
p.end();
*table2 = *table;
bitBlt( this, 0, 0, table2 );
return;
}
drawPerodicTableView( &p, m_currentScheme == CRYSTAL );
paintCurrentSelection();
p.end();
doFullDraw = false;
}
//JH: Ok, now table contains the static PerodicTableView table, and we may need to draw
//a tooltip on it. However, we don't want to ruin the stored table pixmap,
//so let's copy it to table2 and add the tooltip there.
*table2 = *table;
//JH: Finally, bitBlt the table2 pixmap to the widget
bitBlt( this, 0, 0, table2 );
}
void PerodicTableView::paintCurrentSelection()
{
if (m_currentPoint.x() == -1)
return;
int x = (m_currentPoint.x()-1)*ELEMENTSIZE;
int y = m_currentPoint.y()*ELEMENTSIZE;
// make a small gap (ELEMENTSIZE/3) over the rare earths
if (m_currentPoint.y() > 7) y += ELEMENTSIZE/3;
TQPainter p;
p.begin(table);
TQPen pen;
pen.setStyle( Qt::DotLine );
pen.setWidth( 4 );
pen.setColor( TQt::blue );
p.setPen( pen );
p.drawEllipse( x-10,y-10,ELEMENTSIZE+20,ELEMENTSIZE+20 );
pen.setWidth( 3 );
pen.setColor( TQt::red );
p.setPen( pen );
p.drawEllipse( x-5,y-5,ELEMENTSIZE+10,ELEMENTSIZE+10 );
p.end();
}
void PerodicTableView::drawLegendToolTip( TQPainter* p )
{
kdDebug() << "PerodicTableView::drawLegendToolTip()" << endl;
if(!m_showLegendTooltip || !m_showLegend) return;
TQString text;
switch ( m_currentScheme ) {
//No Legend drawn as only one colour is used
case PerodicTableView::NOCOLOUR:
break;
case PerodicTableView::BLOCK:
text = i18n( "The periodic table can be split up into four areas:\n the s-, p-, d- and f-Block. The name indicates which orbit\n is being filled last. For example, all elements in the s-block\n fill up the s-orbits." );
break;
case PerodicTableView::GROUPS:
text = i18n( "The periodic table can be split up into groups:\n All elements in a group show similar behaviour");
break;
case PerodicTableView::ACIDIC:
text = i18n( "The periodic table can be split up in groups of \nelements with different acidic behaviour.");
break;
case PerodicTableView::FAMILY:
text = i18n( "The periodic table can be split up into several families.");
break;
}
const int x1 = mapFromGlobal( TQCursor::pos() ).x();
const int y1 = mapFromGlobal( TQCursor::pos() ).y();
static const int padding = 3;
TQFont fB = KGlobalSettings::generalFont();
fB.setPointSize( fB.pointSize() + 4 );
p->setFont( fB );
TQRect bRect( 0, 0, 1000, 1000 );
bRect = p->boundingRect( bRect, AlignLeft|AlignTop, text );
bRect.moveBy( x1, y1 );
TQRect bRectExt = bRect;
bRect.moveBy( padding, padding );
bRectExt.setWidth( bRectExt.width() + 2 * padding );
bRectExt.setHeight( bRectExt.height() + 2 * padding );
bool vertflipped = false;
if ( bRectExt.bottom() > height() )
{
bRectExt.moveBy( 0, - bRectExt.height() );
bRect.moveBy( 0, - bRect.height() - 2 * padding );
vertflipped = true;
}
if ( bRectExt.right() > width() )
{
bRectExt.moveBy( - bRectExt.width(), 0 );
bRect.moveBy( - bRect.width() - 2 * padding, 0 );
}
else if ( !vertflipped )
{
bRectExt.moveBy( 15, 0 );
bRect.moveBy( 15, 0 );
}
p->setBrush(TQt::SolidPattern);
p->setBrush( TQColor( 255, 255, 220 ) );
p->drawRect( bRectExt );
p->setBrush( TQt::black );
p->setBrush(TQt::NoBrush);
p->drawText( bRect, AlignLeft|AlignTop, text );
}
void PerodicTableView::drawTimeLine( TQPainter* p )
{
if ( !p ) return;
kdDebug() << "PerodicTableView::drawTimeLine: " << m_date << endl;
if ( gradient() )
activateColorScheme( PerodicTableView::NOCOLOUR );
EList::ConstIterator it = d->ElementList.begin();
const EList::ConstIterator itEnd = d->ElementList.end();
bool simple = Prefs::pselook();
/**
* this loop iterates through all elements. The Elements
* draw themselfs, the PerodicTableView only tells them to do so
*/
while ( it != itEnd )
{
if ( ( *it )->date() <= m_date )
( *it )->drawSelf( p, simple );
else
( *it )->drawGrayedOut( p );
++it;
}
}
void PerodicTableView::drawLegend( TQPainter* p )
{
if ( !p ) return;
if ( !m_showLegend ) return;
/*
* The legend is drawn in the big gap of the table. The gap has
* this size:
*
* width: ELEMENTSIZE * 10
* height: ELEMENTSIZE * 3
*
* We need to spare a few pixels on every side so that the legend
* does not collide with the elements
*/
TQFont legendFont = KGlobalSettings::generalFont();
legendFont.setPointSize( legendFont.pointSize() + 1 );
p->setFont( legendFont );
int legendLeft = ELEMENTSIZE * 5 / 2;
int legendTop = ELEMENTSIZE * 3 / 4;
int legendWidth = ELEMENTSIZE * 9;
int legendHeight = ELEMENTSIZE * 3;
int x1 = legendLeft + ELEMENTSIZE / 2;
int x2 = legendLeft + ELEMENTSIZE * 5;
/*
* one field is allowed to be half the gap minus 10 pixel
*/
int fieldsize = ELEMENTSIZE*5-10;
/*
* one field is a maximum of half the size of an element
*/
int fieldheight = ELEMENTSIZE/2;
const int square_w = 18;
const int square_h = 18;
const int textOffset = square_w + 10;
if ( !m_currentScheme == PerodicTableView::NOCOLOUR )
p->fillRect(legendLeft, legendTop, legendWidth, legendHeight,
TQColor(200, 200, 200));
if ( som() )
{
p->fillRect(x1, fieldheight*2, square_w, square_h, c_solid );
p->fillRect(x1, fieldheight*3, square_w, square_h, c_liquid );
p->fillRect(x1, fieldheight*4, square_w, square_h, c_vapor );
p->drawText(x1 + textOffset, fieldheight*2, fieldsize, fieldheight, TQt::AlignLeft, i18n("Solid") );
p->drawText(x1 + textOffset, fieldheight*3, fieldsize, fieldheight, TQt::AlignLeft, i18n("Liquid") );
p->drawText(x1 + textOffset, fieldheight*4, fieldsize, fieldheight, TQt::AlignLeft, i18n("Vaporous") );
return;
}
switch ( m_currentScheme ){
//No Legend to be drawn as only one colour is used
case PerodicTableView::NOCOLOUR:
break;
case PerodicTableView::GROUPS:
p->fillRect( x1, fieldheight*2, square_w, square_h, color_1);
p->fillRect( x1, fieldheight*3, square_w, square_h, color_2);
p->fillRect( x1, fieldheight*4, square_w, square_h, color_3);
p->fillRect( x1, fieldheight*5, square_w, square_h, color_4);
p->fillRect( x2, fieldheight*2, square_w, square_h, color_5);
p->fillRect( x2, fieldheight*3, square_w, square_h, color_6);
p->fillRect( x2, fieldheight*4, square_w, square_h, color_7);
p->fillRect( x2, fieldheight*5, square_w, square_h, color_8 );
p->drawText( x1 + textOffset , fieldheight*2, fieldsize, fieldheight, TQt::AlignLeft, i18n("Group 1") );
p->drawText( x1 + textOffset , fieldheight*3, fieldsize, fieldheight, TQt::AlignLeft, i18n("Group 2"));
p->drawText( x1 + textOffset , fieldheight*4, fieldsize, fieldheight, TQt::AlignLeft, i18n("Group 3"));
p->drawText( x1 + textOffset , fieldheight*5, fieldsize, fieldheight, TQt::AlignLeft, i18n("Group 4"));
p->drawText( x2 + textOffset , fieldheight*2, fieldsize, fieldheight, TQt::AlignLeft, i18n("Group 5"));
p->drawText( x2 + textOffset , fieldheight*3, fieldsize, fieldheight, TQt::AlignLeft, i18n("Group 6"));
p->drawText( x2 + textOffset , fieldheight*4, fieldsize, fieldheight, TQt::AlignLeft, i18n("Group 7"));
p->drawText( x2 + textOffset , fieldheight*5, fieldsize, fieldheight, TQt::AlignLeft, i18n("Group 8"));
break;
case PerodicTableView::BLOCK:
p->fillRect(x1, fieldheight*2, square_w, square_h, color_s );
p->fillRect(x1, fieldheight*3, square_w, square_h, color_p );
p->fillRect(x1, fieldheight*4, square_w, square_h, color_d );
p->fillRect(x1, fieldheight*5, square_w, square_h, color_f );
p->drawText(x1 + textOffset, fieldheight*2, fieldsize, fieldheight, TQt::AlignLeft, i18n("s-Block") );
p->drawText(x1 + textOffset, fieldheight*3, fieldsize, fieldheight, TQt::AlignLeft, i18n("p-Block") );
p->drawText(x1 + textOffset, fieldheight*4, fieldsize, fieldheight, TQt::AlignLeft, i18n("d-Block") );
p->drawText(x1 + textOffset, fieldheight*5, fieldsize, fieldheight, TQt::AlignLeft, i18n("f-Block") );
break;
case PerodicTableView::ACIDIC:
p->fillRect(x1, fieldheight*2, square_w, square_h, color_ba );
p->fillRect(x1, fieldheight*3, square_w, square_h, color_neu );
p->fillRect(x1, fieldheight*4, square_w, square_h, color_ac );
p->fillRect(x1, fieldheight*5, square_w, square_h, color_amp );
p->drawText(x1 + textOffset, fieldheight*2, fieldsize, fieldheight, TQt::AlignLeft, i18n("Basic") );
p->drawText(x1 + textOffset, fieldheight*3, fieldsize, fieldheight, TQt::AlignLeft, i18n("Neutral") );
p->drawText(x1 + textOffset, fieldheight*4, fieldsize, fieldheight, TQt::AlignLeft, i18n("Acidic") );
p->drawText(x1 + textOffset, fieldheight*5, fieldsize, fieldheight, TQt::AlignLeft, i18n("both acidic and basic behaviour","Amphoteric") );
break;
case PerodicTableView::FAMILY:
p->fillRect( x1, fieldheight*2, square_w, square_h, c_alkaline );
p->fillRect( x2, fieldheight*2, square_w, square_h, c_rare );
p->fillRect( x1, fieldheight*3, square_w, square_h, c_nonmetal );
p->fillRect( x2, fieldheight*3, square_w, square_h, c_alkalie );
p->fillRect( x1, fieldheight*4, square_w, square_h, c_other_metal );
p->fillRect( x2, fieldheight*4, square_w, square_h, c_halogene );
p->fillRect( x1, fieldheight*5, square_w, square_h, c_transition );
p->fillRect( x2, fieldheight*5, square_w, square_h, c_noble_gas );
p->fillRect( x1, fieldheight*6, square_w, square_h, c_metalloid );
p->drawText( x1 + textOffset , fieldheight*2, fieldsize, fieldheight, TQt::AlignLeft, i18n("Alkaline") );
p->drawText( x2 + textOffset , fieldheight*2, fieldsize, fieldheight, TQt::AlignLeft, i18n("Rare Earth"));
p->drawText( x1 + textOffset , fieldheight*3, fieldsize, fieldheight, TQt::AlignLeft, i18n("Non-Metals"));
p->drawText( x2 + textOffset , fieldheight*3, fieldsize, fieldheight, TQt::AlignLeft, i18n("Alkalie-Metals"));
p->drawText( x1 + textOffset , fieldheight*4, fieldsize, fieldheight, TQt::AlignLeft, i18n("Other Metal"));
p->drawText( x2 + textOffset , fieldheight*4, fieldsize, fieldheight, TQt::AlignLeft, i18n("Halogene"));
p->drawText( x1 + textOffset , fieldheight*5, fieldsize, fieldheight, TQt::AlignLeft, i18n("Transition Metal"));
p->drawText( x2 + textOffset , fieldheight*5, fieldsize, fieldheight, TQt::AlignLeft, i18n("Noble Gas"));
p->drawText( x1 + textOffset , fieldheight*6, fieldsize, fieldheight, TQt::AlignLeft, i18n("Metalloid"));
break;
case PerodicTableView::CRYSTAL:
p->fillRect(x1, fieldheight*2, square_w, square_h, TQt::cyan );
p->fillRect(x1, fieldheight*3, square_w, square_h, TQt::red );
p->fillRect(x1, fieldheight*4, square_w, square_h, TQt::yellow );
p->fillRect(x1, fieldheight*5, square_w, square_h, TQt::green );
p->fillRect(x1, fieldheight*6, square_w, square_h, TQt::white );
p->drawText(x1 + textOffset, fieldheight*2, fieldsize, fieldheight, TQt::AlignLeft, i18n("Own") );
p->drawText(x1 + textOffset, fieldheight*3, fieldsize, fieldheight, TQt::AlignLeft, i18n("bcc, body centered cubic") );
p->drawText(x1 + textOffset, fieldheight*4, fieldsize, fieldheight, TQt::AlignLeft, i18n("hdp, hexagonal") );
p->drawText(x1 + textOffset, fieldheight*5, fieldsize, fieldheight, TQt::AlignLeft, i18n("ccp, cubic close packed") );
p->drawText(x1 + textOffset, fieldheight*6, fieldsize, fieldheight, TQt::AlignLeft, i18n("Unknown") );
break;
}
}
void PerodicTableView::drawNumeration( TQPainter* p )
{
if ( !p ) return;
switch(m_num){
case PerodicTableView::NO:
return;
case PerodicTableView::CAS:
for(int i = 0; i < 18 ; ++i )
{
p->drawText( i*ELEMENTSIZE,0 ,ELEMENTSIZE,ELEMENTSIZE, TQt::AlignCenter, TQString::number(i+1));
}
break;
case PerodicTableView::IUPAC:
for(int i = 0; i < 18 ; ++i )
{
p->drawText( i*ELEMENTSIZE,0 ,ELEMENTSIZE,ELEMENTSIZE, TQt::AlignCenter, m_IUPAClist[i]);
}
break;
case PerodicTableView::IUPACOLD:
for(int i = 0; i < 18 ; ++i )
{
p->drawText( i*ELEMENTSIZE,0 ,ELEMENTSIZE,ELEMENTSIZE, TQt::AlignCenter, m_IUPACOLDlist[i]);
}
break;
}
}
void PerodicTableView::drawSOMPerodicTableView( TQPainter* p )
{
EList::ConstIterator it = d->ElementList.begin();
const EList::ConstIterator itEnd = d->ElementList.end();
while ( it != itEnd )
{
( *it )->drawStateOfMatter( p, m_temperature );
++it;
}
}
void PerodicTableView::slotTransientLabel()
{
TQPoint point = ElementUnderMouse();
int X = point.x();
int Y = point.y();
const int num = ElementNumber( X, Y );
if ( num )
emit ToolTip( num );
else if ( pointerOnLegend( X, Y ) ) //show the tooltip for the lengend
{
m_showLegendTooltip = true;
update();
}
else
m_showLegendTooltip = false;
}
void PerodicTableView::mousePressEvent( TQMouseEvent *)
{
if( m_kalziumTip->isVisible() )
m_kalziumTip->hide();
}
void PerodicTableView::mouseMoveEvent( TQMouseEvent * /*mouse*/ )
{
//JH: only update() if we were showing a tooltip
if ( m_tooltipElementNumber || m_showLegendTooltip )
{
//this invalidates the number. If the mouse
//is moved, the number is invalid.
m_tooltipElementNumber = 0;
m_showLegendTooltip = false;
update();
}
if( m_kalziumTip->isVisible() )
{
// kdDebug()<< "visible" << endl;
TQPoint point = ElementUnderMouse();
int X = point.x();
int Y = point.y();
const int num = ElementNumber( X, Y );
if ( num != 0 )
emit ToolTip( num );
else
m_kalziumTip->hide();
}
HoverTimer.start( 500, true ); //JH: true = run timer once, not continuously
MouseoverTimer.start( 200, true ); //JH: true = run timer once, not continuously
}
bool PerodicTableView::pointerOnLegend(int X, int Y)
{
if ( X > 2 && X < 13 )
{
if ( Y < 4 && Y > 0 )
{
return true;
}
}
return false;
}
void PerodicTableView::mouseReleaseEvent( TQMouseEvent *mouse )
{
///first: find out the position
int X = mouse->x()/ELEMENTSIZE;
//for the y-position I need to substract ELEMENTSIZE pixel because
//the whole table doesn't start at (0,0) but at (0,ELEMENTSIZE)
int Y = mouse->y()-ELEMENTSIZE;
// ignore clicks on the small gap over rare earth
if (Y >= (ELEMENTSIZE*7) && Y < (ELEMENTSIZE*7+ELEMENTSIZE/3+1)) return;
// mind the gap!
if (Y > (ELEMENTSIZE*7)) Y -= ELEMENTSIZE/3;
Y /= ELEMENTSIZE;
X += 1;
Y += 1;
TQPoint point( X,Y );
emit tableClicked( point );
const int num = ElementNumber( X, Y );
//kdDebug() << "Element clicked: " << num << endl;
//If no element was clicked ElementNumber() will return 0
if ( num ) {
emit ElementClicked( num );
selectPoint( point );
}
}
int PerodicTableView::ElementNumber( int X, int Y )
{
//from this on I can use X and Y. Both contain the position of an element in the
//complete PerodicTableView. Eg, He is 1,18 and Na is 2,1
CList::ConstIterator it = d->CoordinateList.begin();
const CList::ConstIterator itEnd = d->CoordinateList.end();
int counter = 1;
while ( it != itEnd )
{//iterate through the list of coordinates and compare the x/y values.
//finally, if the 20'es iterator has the same coordinates Element 20
//has been clicked.
coordinate c = *it;
if ( c.x == X )
{
if ( c.y == Y )
{//coordinates match. Return the number of the element.
return counter;
}
}
++it;
++counter;
}
return 0;
}
void PerodicTableView::unSelect()
{
m_currentPoint = TQPoint(-1, -1);
// Full draw needed to redraw the select mark.
setFullDraw();
update();
}
void PerodicTableView::selectPoint( const TQPoint& point )
{
kdDebug() << "PerodicTableView::selectPoint " << point << endl;
m_currentPoint = point;
// Full draw needed to redraw the select mark.
setFullDraw();
update();
}
void PerodicTableView::selectElement( int num )
{
kdDebug() << "PerodicTableView::selectElement " << num << endl;
selectPoint( d->element( num )->coords() );
}
void PerodicTableView::drawPerodicTableView( TQPainter* p, bool isCrystal )
{
EList::ConstIterator it = d->ElementList.begin();
const EList::ConstIterator itEnd = d->ElementList.end();
bool simple = Prefs::pselook();
/**
* this loop iterates through all elements. The Elements
* draw themselfs, the PerodicTableView only tells them to do so
*/
while ( it != itEnd )
{
( *it )->drawSelf( p, simple, isCrystal );
++it;
}
}
//CN This is called for *every* drawing of the table. This means
//a lot overload... I would be better to chache the values in
//member variables an only check if they need an update.
void PerodicTableView::calculateGradient( TQPainter *p )
{
EList::ConstIterator it = d->ElementList.begin();
const EList::ConstIterator itEnd = d->ElementList.end();
TQValueList<double> tmpList;
switch ( m_gradientType )
{
case Element::ATOMICRADIUS:
for (; it != itEnd; ++it )
{
tmpList.append( ( *it )->radius(Element::ATOMIC) );
}
break;
case Element::COVALENTRADIUS:
for (; it != itEnd; ++it )
{
tmpList.append( ( *it )->radius(Element::COVALENT) );
}
break;
case Element::VDWRADIUS:
for (; it != itEnd; ++it )
{
tmpList.append( ( *it )->radius(Element::VDW) );
}
break;
case Element::MASS:
for (; it != itEnd; ++it )
{
tmpList.append( ( *it )->mass() );
}
break;
case Element::DENSITY:
for (; it != itEnd; ++it )
{
tmpList.append( ( *it )->density() );
}
break;
case Element::BOILINGPOINT:
for (; it != itEnd; ++it )
{
tmpList.append( ( *it )->boiling() );
}
break;
case Element::MELTINGPOINT:
for (; it != itEnd; ++it )
{
tmpList.append( ( *it )->melting() );
}
break;
case Element::EN:
for (; it != itEnd; ++it )
{
tmpList.append( ( *it )->electroneg() );
}
break;
case Element::EA:
for (; it != itEnd; ++it )
{
tmpList.append( ( *it )->electroaf() );
}
break;
}
TQValueList<double>::iterator dit = tmpList.begin();
const TQValueList<double>::iterator ditEnd = tmpList.end();
double tmpMin = *dit;
double tmpMax = *dit;
for ( ; dit != ditEnd; ++dit )
{
if (( *dit ) == 0 ) continue;
if ( ( *dit ) < tmpMin )
tmpMin = *dit;
if ( ( *dit ) > tmpMax )
tmpMax = *dit;
}
//now draw the gradient-table
drawGradientPerodicTableView( p, tmpMin, tmpMax );
}
void PerodicTableView::drawGradientPerodicTableView( TQPainter *p, const double min, const double max )
{
TQString title = TQString();
const double var = max-min;
EList::ConstIterator it = d->ElementList.begin();
const EList::ConstIterator itEnd = d->ElementList.end();
/**
* this loop iterates through all elements. The Elements
* draw themselves, the PerodicTableView only tells them to do so
*/
it = d->ElementList.begin();
switch ( m_gradientType )
{
case Element::ATOMICRADIUS:
title = i18n( "Gradient: Atomic Radius" );
while ( it != d->ElementList.end() )
{
double value = ( *it )->radius( Element::ATOMIC );
double coeff = ( value - min )/var;
drawGradientButton( p, *it, coeff, value, min );
++it;
}
break;
case Element::VDWRADIUS:
title = i18n( "Gradient: van der Waals Radius" );
while ( it != d->ElementList.end() )
{
double value = ( *it )->radius( Element::VDW );
double coeff = ( value - min )/var;
drawGradientButton( p, *it, coeff, value, min );
++it;
}
break;
case Element::COVALENTRADIUS:
title = i18n( "Gradient: Covalent Radius" );
while ( it != d->ElementList.end() )
{
double value = ( *it )->radius( Element::COVALENT );
double coeff = ( (*it)->radius(Element::COVALENT) - min )/var;
drawGradientButton( p, *it, coeff, value, min );
++it;
}
break;
case Element::MASS:
title = i18n( "Gradient: Atomic Mass" );
while ( it != d->ElementList.end() )
{
double coeff = ( (*it)->mass() - min )/var;
drawGradientButton( p, *it, coeff, ( *it )->mass(), min );
++it;
}
break;
case Element::DENSITY:
title = i18n( "Gradient: Atomic Density" );
while ( it != d->ElementList.end() )
{
double coeff = ( (*it)->density() - min )/var;
drawGradientButton( p, *it, coeff, ( *it )->density(), min );
++it;
}
break;
case Element::BOILINGPOINT:
title = i18n( "Gradient: Boiling point" );
while ( it != d->ElementList.end() )
{
double coeff = ( (*it)->boiling() - min )/var;
drawGradientButton( p, *it, coeff, ( *it )->boiling(), min );
++it;
}
break;
case Element::MELTINGPOINT:
title = i18n( "Gradient: Melting point" );
while ( it != d->ElementList.end() )
{
double coeff = ( (*it)->melting() - min )/var;
drawGradientButton( p, *it, coeff, ( *it )->melting(), min );
++it;
}
break;
case Element::EN:
title = i18n( "Gradient: Electronegativity" );
while ( it != d->ElementList.end() )
{
double coeff = ( (*it)->electroneg() - min )/var;
drawGradientButton( p, *it, coeff, ( *it )->electroneg(), min );
++it;
}
break;
case Element::EA:
title = i18n( "Gradient: Electron affinity" );
double tmpVar = -1*(min - max);
while ( it != d->ElementList.end() )
{
if( (*it)->electroaf() == 0.0)
drawGradientButton( p, *it,-1.0, (*it )->electroaf(), min );
else
{
double coeff = ( max - (*it)->electroaf() )/tmpVar;
drawGradientButton( p, *it, coeff, (*it )->electroaf(), min );
}
++it;
}
break;
}
// Now draw the legend.
int x = ELEMENTSIZE*2+5;
int y = 5;
//int w = ELEMENTSIZE*10-5;
//int h = ELEMENTSIZE*4-5;
// Create the gradient image.
TQSize s( ELEMENTSIZE*7+20, 20 );
TQImage img = KImageEffect::gradient ( s, TQt::white, TQt::red,
KImageEffect::HorizontalGradient );
TQPixmap pm( img );
/**
* now find the optimum stringsize for the caption
* i18n( "Gradient: van der Waals Radius" ); is at least
* for english the longest possible string. As "van der Waals"
* is a name it should be the same in all languages and be
* probably always the longest string
*/
TQString tmp = i18n( "Gradient: van der Waals Radius" );
TQRect rect(x+5, y+50, ELEMENTSIZE*10,20);
TQFont font = p->font();
int maxSize = KalziumUtils::maxSize( tmp, rect, p->font(), p, 8, 24 );
kdDebug() << "maxSize: " << maxSize << endl;
font.setPointSize(maxSize);
p->setFont(font);
p->drawText( x+5, y+50, ELEMENTSIZE*10,20, TQt::AlignCenter, title );
p->drawPixmap( x+50, y+80, pm );
if ( m_gradientType == Element::EA )
{
// FIXME: In the lines below, "30" is the max allowed text
// height. This should be calculated from the font
// metrics, not hard coded.
p->drawText( x+50,y+100,ELEMENTSIZE*7+20,30, TQt::AlignRight, TQString::number( min ) );
p->drawText( x+50,y+100,ELEMENTSIZE*7+20,30, TQt::AlignLeft, TQString::number( max ) );
}
else
{
p->drawText( x+50,y+100,ELEMENTSIZE*7+20,30, TQt::AlignRight, TQString::number( max ) );
p->drawText( x+50,y+100,ELEMENTSIZE*7+20,30, TQt::AlignLeft, TQString::number( min ) );
}
}
TQPoint PerodicTableView::ElementUnderMouse()
{
int X = mapFromGlobal( TQCursor::pos() ).x()/ELEMENTSIZE;
int Y = mapFromGlobal( TQCursor::pos() ).y( )-ELEMENTSIZE;
// mind the gap over rare earth!
if (Y >= (ELEMENTSIZE*7) && Y < (ELEMENTSIZE*7+ELEMENTSIZE/3+1)) return TQPoint( 0, 0 );
if (Y > (ELEMENTSIZE*7)) Y -= ELEMENTSIZE/3;
Y /= ELEMENTSIZE;
X += 1;
Y += 1;
return TQPoint( X,Y );
}
void PerodicTableView::slotMouseover()
{
TQPoint point = ElementUnderMouse();
int num = ElementNumber( point.x(), point.y() );
if ( num )
emit MouseOver( num );
}
void PerodicTableView::drawGradientButton( TQPainter *p, Element* e, double coeff, double value, double minValue )
{
if ( value >= minValue && coeff != -1.0)
{
TQColor c = calculateColor( coeff );
TQString v = KalziumUtils::localizedValue( KalziumUtils::strippedValue( value ), 6 );
e->drawGradient( p, v, c );
}
else
e->drawGradient( p, i18n("It means: Not Available. Translators: keep it as short as you can!", "N/A"), TQt::lightGray );
}
TQColor PerodicTableView::calculateColor( const double coeff )
{
const TQColor color2 = TQt::white;
const TQColor color1 = TQt::red;
int red = (int)( (color1.red() - color2.red()) * coeff + color2.red() );
int green = (int)( (color1.green() - color2.green()) * coeff + color2.green() );
int blue = (int)( (color1.blue() - color2.blue()) * coeff + color2.blue() );
return TQColor( red, green, blue );
}
void PerodicTableView::setLook( PerodicTableView::SCHEMETYPE type, int which )
{
m_currentScheme = type;
EList::ConstIterator it = d->ElementList.begin();
const EList::ConstIterator itEnd = d->ElementList.end();
switch ( type )
{
case NOCOLOUR:
{
const TQColor color = Prefs::noscheme();
while ( it != itEnd )
{
( *it )->setElementColor( color );
++it;
}
setGradient( false );
break;
}
case PerodicTableView::GROUPS: // group view
{
TQString group;
while ( it != itEnd )
{
group = ( *it )->group();
if (group == TQString("1")) {
( *it )->setElementColor( color_1 );
}
if (group == TQString("2")){
( *it )->setElementColor( color_2 );
}
if (group == TQString("3")){
( *it )->setElementColor( color_3 );
}
if (group == TQString("4")){
( *it )->setElementColor( color_4 );
}
if (group == TQString("5")){
( *it )->setElementColor( color_5 );
}
if (group == TQString("6")){
( *it )->setElementColor( color_6 );
}
if (group == TQString("7")){
( *it )->setElementColor( color_7 );
}
if (group == TQString("8")){
( *it )->setElementColor( color_8 );
}
++it;
}
setGradient( false );
break;
}
case PerodicTableView::BLOCK: //block view
{
static TQString block;
while ( it != itEnd )
{
block = (*it)->block();
if (block == TQString("s")) {
(*it)->setElementColor( color_s );
}
if (block == TQString("p")) {
(*it)->setElementColor( color_p );
}
if (block == TQString("d")) {
(*it)->setElementColor( color_d );
}
if (block == TQString("f")) {
(*it)->setElementColor( color_f );
}
++it;
}
setGradient( false );
break;
}
case PerodicTableView::ACIDIC: //acidic beh
{
static TQString acidicbeh;
while ( it != itEnd )
{
acidicbeh = ( *it )->acidicbeh();
if (acidicbeh == TQString("0")) {
(*it)->setElementColor( color_ac );
}
if (acidicbeh == TQString("1")){
(*it)->setElementColor( color_ba );
}
if (acidicbeh == TQString("2")){
(*it)->setElementColor( color_neu );
}
if (acidicbeh == TQString("3")){
(*it)->setElementColor( color_amp );
}
++it;
}
setGradient( false );
break;
}
case PerodicTableView::FAMILY: //familiy of the element
{
static TQString family;
while ( it != itEnd )
{
family = ( *it )->family();
if ( family == "Noblegas" ){
(*it)->setElementColor( c_noble_gas );
}
if ( family == "Non-Metal" ){
(*it)->setElementColor( c_nonmetal );
}
if ( family == "Rare_Earth" ){
(*it)->setElementColor( c_rare );
}
if ( family == "Alkaline_Earth" ){
(*it)->setElementColor( c_alkaline );
}
if ( family == "Alkali_Earth" ){
(*it)->setElementColor( c_alkalie );
}
if ( family == "Transition" ){
(*it)->setElementColor( c_transition );
}
if ( family == "Other_Metal" ){
(*it)->setElementColor( c_other_metal );
}
if ( family == "Metalloids" ){
(*it)->setElementColor( c_metalloid );
}
if ( family == "Halogene" ){
(*it)->setElementColor( c_halogene );
}
++it;
}
setGradient( false );
break;
}
case CRYSTAL:
{
TQString structure;
while ( it != itEnd )
{
structure = ( *it )->crystalstructure();
if ( structure == "own")
(*it)->setElementColor( TQt::cyan );
else if ( structure == "bcc" )
(*it)->setElementColor( TQt::red );
else if ( structure == "hdp" )
(*it)->setElementColor( TQt::yellow );
else if ( structure == "ccp" )
(*it)->setElementColor( TQt::green );
else
(*it)->setElementColor( TQt::white );
++it;
}
setGradient( false );
break;
}
case GRADIENT:
{
setGradient( true );
setGradientType( which );
break;
}
default:
;
}
Prefs::setColorschemebox( type );
Prefs::writeConfig();
//JH: redraw the full table next time
setFullDraw();
update();
}
#include "periodictableview.moc"