/*************************************************************************** * Copyright (C) 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 "spectrumwidget.h" #include "spectrum.h" #include "element.h" #include "kalziumutils.h" #include #include #include #include #include #include #include #include #include #include #if defined(Q_OS_SOLARIS) #include #endif SpectrumWidget::SpectrumWidget( TQWidget *parent, const char* name ) : TQWidget( parent, name ) { startValue = 0; endValue = 0; m_LMBPointCurrent.setX( -1 ); m_LMBPointPress.setX( -1 ); m_showtooltip = false; m_realHeight = 200; Gamma = 0.8; IntensityMax = 255; setType( EmissionSpectrum ); setMinimumSize( 400, 230 ); setSizePolicy( TQSizePolicy::Expanding, TQSizePolicy::Expanding ); setBackgroundMode( NoBackground ); } void SpectrumWidget::paintEvent( TQPaintEvent * /*e*/ ) { if ( !m_spectrum ) return; m_pixmap.resize( width(), height() ); m_pixmap.fill( this, width(), height() ); TQPainter p; p.tqbegin( &m_pixmap, this ); p.fillRect( 0, 0, width(), m_realHeight, TQt::black ); paintBands( &p ); drawTickmarks( &p ); if ( m_showtooltip ) drawTooltip( &p ); if ( m_LMBPointPress.x() != -1 && m_LMBPointCurrent.x() != -1 ) drawZoomLine( &p ); p.end(); bitBlt( this, 0, 0, &m_pixmap ); } void SpectrumWidget::drawZoomLine( TQPainter* p ) { p->setPen( TQt::white ); p->drawLine( m_LMBPointPress.x(), m_LMBPointPress.y(), m_LMBPointCurrent.x(), m_LMBPointPress.y() ); p->drawLine( m_LMBPointCurrent.x(), m_LMBPointPress.y()+10, m_LMBPointCurrent.x(), m_LMBPointPress.y()-10 ); p->drawLine( m_LMBPointPress.x(), m_LMBPointPress.y()+10, m_LMBPointPress.x(), m_LMBPointPress.y()-10 ); } void SpectrumWidget::paintBands( TQPainter* p ) { if ( m_type == AbsorptionSpectrum ) { for ( double va = startValue; va <= endValue ; va += 0.1 ) { int x = xPos( va ); p->setPen( linecolor( va ) ); p->drawLine( x,0,x, m_realHeight ); } p->setPen( TQt::black ); } int i = 0; int x = 0; int temp = 0; for ( TQValueList::Iterator it = m_spectrum->bandlist()->begin(); it != m_spectrum->bandlist()->end(); ++it ) { if ( ( *it ).wavelength < startValue || ( *it ).wavelength > endValue ) continue; x = xPos( ( *it ).wavelength ); temp = 0; switch ( m_type ) { case EmissionSpectrum: p->setPen( linecolor( ( *it ).wavelength ) ); p->drawLine( x,0,x, m_realHeight-1 ); p->setPen( TQt::black ); // p->drawLine( x,m_realHeight,x, m_realHeight ); break; case AbsorptionSpectrum: p->setPen( TQt::black ); p->drawLine( x,0,x, m_realHeight-1 ); break; } i++; } } TQColor SpectrumWidget::linecolor( double spectrum ) { int r,g,b; wavelengthToRGB( spectrum, r,g,b ); TQColor c( r,g,b ); return c; } void SpectrumWidget::wavelengthToRGB( double wavelength, int& r, int& g, int& b ) { double blue = 0.0, green = 0.0, red = 0.0, factor = 0.0; int wavelength_ = ( int ) floor( wavelength ); if ( wavelength_ < 380 || wavelength_ > 780 ) { //make everything white r = g = b = 255; return; } else if ( wavelength_ > 380 && wavelength_ < 439 ) { red = -( wavelength-440 ) / ( 440-380 ); green = 0.0; blue = 1.0; } else if ( wavelength_ > 440 && wavelength_ < 489 ) { red = 0.0; green = ( wavelength-440 ) / ( 490-440 ); blue = 1.0; } else if ( wavelength_ > 490 && wavelength_ < 509 ) { red = 0.0; green = 1.0; blue = -( wavelength-510 ) / ( 510-490 ); } else if ( wavelength_ > 510 && wavelength_ < 579 ) { red = ( wavelength-510 ) / ( 580-510 ); green = 1.0; blue = 0.0; } else if ( wavelength_ > 580 && wavelength_ < 644 ) { red = 1.0; green = -( wavelength-645 ) / ( 645-580 ); blue = 0.0; } else if ( wavelength_ > 645 && wavelength_ < 780 ) { red = 1.0; green = 0.0; blue = 0.0; } if ( wavelength_ > 380 && wavelength_ < 419 ) factor = 0.3 + 0.7*( wavelength - 380 ) / ( 420 - 380 ); else if ( wavelength_ > 420 && wavelength_ < 700 ) factor = 1.0; else if ( wavelength_ > 701 && wavelength_ < 780 ) factor = 0.3 + 0.7*( 780 - wavelength ) / ( 780 - 700 ); else factor = 0.0; r = Adjust( red, factor ); g = Adjust( green, factor ); b = Adjust( blue, factor ); } int SpectrumWidget::Adjust( double color, double factor ) { if ( color == 0.0 ) return 0; else return tqRound( IntensityMax * pow( color*factor, Gamma ) ); } void SpectrumWidget::drawTickmarks( TQPainter* p ) { //the size of the text on the tickmarks const int space = 20; //the distance between the tickmarks in pixel const int d = 10; //the total number of tickmarks to draw (small and long) const int numberOfTickmarks = ( int )floor( width()/d ); double pos = 0.0; for ( int i = 0; i < numberOfTickmarks; i++ ) { if( i%5 == 0 ) {//long tickmarks plus text p->drawLine( i*d, m_realHeight, i*d, m_realHeight+10 ); if ( i%10 == 0 && i*d > space && i*d < width()-space ) { pos = ( double ) ( i*d )/width(); p->fillRect( i*d-space, m_realHeight+12, 2*space, 15, TQt::white ); p->drawText( i*d-space, m_realHeight+12, 2*space, 15, TQt::AlignCenter, KalziumUtils::localizedValue( KalziumUtils::strippedValue( Wavelength( pos ) ), 6 ) ); } } else {//small tickmarks p->drawLine( i*d, m_realHeight, i*d, m_realHeight+5 ); } } } void SpectrumWidget::keyPressEvent( TQKeyEvent *e ) { kdDebug() << "SpectrumWidget::keyPressEvent()" << endl; switch ( e->key() ) { case Key_Plus: slotZoomIn(); break; case Key_Minus: slotZoomOut(); break; } } void SpectrumWidget::slotZoomOut() { kdDebug() << "SpectrumWidget::slotZoomOut() "<< startValue << ":: "<< endValue << endl; double diff = endValue - startValue; double offset = diff * 0.05; endValue = endValue + offset; startValue = startValue - offset; //check for invalid values if ( startValue < 0.0 ) startValue = 0.0; if ( endValue > 800.0 ) endValue = 800.0; setBorders( ( int ) startValue, ( int )endValue ); kdDebug() << "SpectrumWidget::slotZoomOut() "<< startValue << ":: "<< endValue << endl; } void SpectrumWidget::slotZoomIn() { kdDebug() << "SpectrumWidget::slotZoomIn() "<< startValue << ":: "<< endValue << endl; double diff = endValue - startValue; double offset = diff * 0.05; endValue = endValue - offset; startValue = startValue + offset; setBorders( ( int ) startValue, ( int )endValue ); kdDebug() << "SpectrumWidget::slotZoomIn() "<< startValue << ":: "<< endValue << endl; } void SpectrumWidget::mouseMoveEvent( TQMouseEvent *e ) { m_LMBPointCurrent = e->pos(); update(); } void SpectrumWidget::mousePressEvent( TQMouseEvent *e ) { if ( e->button() == Qt::LeftButton ) m_LMBPointPress = e->pos(); if ( e->button() == Qt::RightButton ) slotZoomOut(); //FIXME //the tooltip is not really working. Better to not have it //in KDE 3.4 and think of a better solution. //PrepareTooltip( Wavelength( ( double )e->pos().x()/width() ) ); } void SpectrumWidget::PrepareTooltip( double wavelength ) { Spectrum::band band; TQValueList::const_iterator it = m_spectrum->bandlist()->begin(); const TQValueList::const_iterator itEnd = m_spectrum->bandlist()->end(); //find the difference in percent (1.0 is 100%, 0.1 is 10%) double dif = 0.0; bool foundWavelentgh = false; //find the highest intensity for ( ; it != itEnd; ++it ) { double thisdif = ( *it ).wavelength / wavelength; if ( thisdif < 0.9 || thisdif > 1.1 ) continue; if ( thisdif > 1.0 ){//convert for example 1.3 to 0.7 thisdif = thisdif-1; thisdif = 1-thisdif; } if ( thisdif > dif ) { dif = thisdif; band = *it; foundWavelentgh = true; } } if ( foundWavelentgh ) { m_band = band; m_showtooltip = true; } else m_showtooltip = false; kdDebug() << "SpectrumWidget::PrepareTooltip(): "<< m_showtooltip << endl; update(); } void SpectrumWidget::drawTooltip( TQPainter *p ) { p->setPen( TQt::white ); TQPoint pt = mapFromGlobal( TQCursor::pos() ); p->drawText( pt, i18n("Wavelength: %1").tqarg(m_band.wavelength) ); pt.setY( pt.y() + 15 ); p->drawText( pt, i18n("Intensity: %1").tqarg(m_band.intensity) ); pt.setY( pt.y() + 15 ); p->drawText( pt, i18n("Energy 1, Energy 2: %1, %2").tqarg(m_band.energy1).tqarg( m_band.energy2 )); pt.setY( pt.y() + 15 ); p->drawText( pt, i18n("Term 1, Term 2: %1, %2").tqarg(m_band.term1).tqarg( m_band.term2 )); pt.setY( pt.y() + 15 ); p->drawText( pt, i18n("J 1, J 2: %1, %2").tqarg(m_band.J1).tqarg( m_band.J2 )); } void SpectrumWidget::mouseReleaseEvent( TQMouseEvent *e ) { if ( e->button() == Qt::LeftButton ) { int left = (int)Wavelength( ( double )m_LMBPointPress.x()/width() ); int right = (int)Wavelength( ( double )e->pos().x()/width() ); if ( left == right ) return; if ( left > right ) setBorders( right, left ); else setBorders( left, right ); } m_LMBPointPress.setX( -1 ); m_LMBPointCurrent.setX( -1 ); } TQPixmap SpectrumWidget::pixmap() { TQPixmap tmp( m_pixmap ); TQString text; if( m_type == EmissionSpectrum ) text = i18n( "Emission spectrum of %1" ).tqarg( m_spectrum->parentElement()->elname() ); else text = i18n( "Absorption spectrum of %1" ).tqarg( m_spectrum->parentElement()->elname() ); TQPainter p( &tmp ); p.setPen( TQt::black ); p.drawText( 30, m_realHeight + 70, text ); return tmp; } #include "spectrumwidget.moc"