/*************************************************************************** * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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( 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 tqrepaint... 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 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::iterator dit = tmpList.begin(); const TQValueList::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"