///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2019- Equinor ASA // // ResInsight 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 3 of the License, or // (at your option) any later version. // // ResInsight 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 at // for more details. // ///////////////////////////////////////////////////////////////////////////////// #include "RiuScalarMapperLegendFrame.h" #include "cvfScalarMapperDiscreteLinear.h" #include "cvfScalarMapperDiscreteLog.h" #include "cvfString.h" #include "cvfqtUtils.h" #include #include #include #include //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RiuScalarMapperLegendFrame::RiuScalarMapperLegendFrame( QWidget* parent, const QString& title, cvf::ScalarMapper* scalarMapper ) : RiuAbstractLegendFrame( parent, title ) , m_scalarMapper( scalarMapper ) , m_tickNumberPrecision( 4 ) , m_numberFormat( RiaNumberFormat::NumberFormatType::AUTO ) { if ( m_scalarMapper.notNull() ) { m_scalarMapper->majorTickValues( &m_tickValues ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RiuScalarMapperLegendFrame::~RiuScalarMapperLegendFrame() { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiuScalarMapperLegendFrame::setTickPrecision( int precision ) { m_tickNumberPrecision = precision; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiuScalarMapperLegendFrame::setTickFormat( NumberFormat format ) { m_numberFormat = format; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiuScalarMapperLegendFrame::layoutInfo( LayoutInfo* layout ) const { QFontMetrics fontMetrics( this->font() ); QStringList titleLines = m_title.split( "\n", QString::SkipEmptyParts ); layout->charHeight = fontMetrics.height(); layout->charAscent = fontMetrics.ascent(); layout->lineSpacing = fontMetrics.lineSpacing(); layout->margins = QMargins( 8, 8, 8, 8 ); layout->tickTextLeadSpace = 5; int colorBarWidth = 25; int colorBarHeight = layout->overallLegendSize.height() - layout->margins.top() - layout->margins.bottom() - titleLines.size() * layout->lineSpacing - 1.0 * layout->lineSpacing; int colorBarStartY = layout->margins.top() + titleLines.size() * layout->lineSpacing + 1.0 * layout->lineSpacing; layout->colorBarRect = QRect( layout->margins.left(), colorBarStartY, colorBarWidth, colorBarHeight ); layout->tickStartX = layout->margins.left(); layout->tickMidX = layout->margins.left() + layout->colorBarRect.width(); layout->tickEndX = layout->tickMidX + 5; // Build array containing the pixel positions of all the ticks int numTicks = (int)m_tickValues.size(); layout->tickYPixelPos.reserve( numTicks ); int i; for ( i = 0; i < numTicks; i++ ) { double t = 0.0; if ( m_scalarMapper.notNull() ) { t = std::clamp( m_scalarMapper->normalizedValue( m_tickValues[i] ), 0.0, 1.1 ); } if ( i == 0 ) { layout->tickYPixelPos.push_back( 0.0 ); } else if ( i == numTicks - 1 ) { layout->tickYPixelPos.push_back( layout->colorBarRect.height() ); } else { layout->tickYPixelPos.push_back( t * layout->colorBarRect.height() ); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RiuScalarMapperLegendFrame::label( int index ) const { double tickValue = m_tickValues[index]; return RiaNumberFormat::valueToText( tickValue, m_numberFormat, m_tickNumberPrecision ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- int RiuScalarMapperLegendFrame::labelCount() const { return (int)m_tickValues.size(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- int RiuScalarMapperLegendFrame::rectCount() const { return (int)m_tickValues.size() - 1; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiuScalarMapperLegendFrame::renderRect( QPainter* painter, const LayoutInfo& layout, int rectIndex ) const { int rectIndexFromBottom = rectCount() - rectIndex - 1; cvf::Color3ub startColor = m_scalarMapper->mapToColor( m_tickValues[rectIndexFromBottom] ); cvf::Color3ub endColor = m_scalarMapper->mapToColor( m_tickValues[rectIndexFromBottom + 1] ); if ( dynamic_cast( m_scalarMapper.p() ) || dynamic_cast( m_scalarMapper.p() ) ) { // Do not draw gradient for discrete legends endColor = startColor; } QColor startQColor( startColor.r(), startColor.g(), startColor.b() ); QColor endQColor( endColor.r(), endColor.g(), endColor.b() ); QRectF gradientRect( QPointF( layout.tickStartX, layout.colorBarRect.bottom() - layout.tickYPixelPos[rectIndexFromBottom] + 1 ), QPointF( layout.tickStartX, layout.colorBarRect.bottom() - layout.tickYPixelPos[rectIndexFromBottom + 1] + 1 ) ); QLinearGradient gradient( gradientRect.topLeft(), gradientRect.bottomRight() ); gradient.setCoordinateMode( QGradient::LogicalMode ); gradient.setColorAt( 0.0, startQColor ); gradient.setColorAt( 1.0, endQColor ); QRectF rect( QPointF( layout.tickStartX, layout.colorBarRect.bottom() - layout.tickYPixelPos[rectIndexFromBottom] + 1 ), QPointF( layout.tickMidX, layout.colorBarRect.bottom() - layout.tickYPixelPos[rectIndexFromBottom + 1] + 1 ) ); painter->fillRect( rect, QBrush( gradient ) ); painter->drawLine( QPointF( layout.tickStartX, layout.colorBarRect.bottom() - layout.tickYPixelPos[rectIndexFromBottom] + 1 ), QPointF( layout.tickEndX, layout.colorBarRect.bottom() - layout.tickYPixelPos[rectIndexFromBottom] + 1 ) ); painter->drawLine( QPointF( layout.tickStartX, layout.colorBarRect.bottom() - layout.tickYPixelPos[rectIndexFromBottom + 1] + 1 ), QPointF( layout.tickEndX, layout.colorBarRect.bottom() - layout.tickYPixelPos[rectIndexFromBottom + 1] + 1 ) ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QRect RiuScalarMapperLegendFrame::labelRect( const LayoutInfo& layout, int index ) const { const int posX = layout.tickEndX + layout.tickTextLeadSpace; QString labelI = this->label( index ); int width = this->fontMetrics().boundingRect( labelI ).width() + 4; int height = layout.lineSpacing; int posY = layout.colorBarRect.bottom() - layout.tickYPixelPos[index]; if ( index + 1 < labelCount() ) { int posYp1 = layout.colorBarRect.bottom() - layout.tickYPixelPos[index + 1]; height = std::min( height, std::abs( posY - posYp1 ) ); } return QRect( posX, posY - height / 2, width, height ); }