1 /*
2     KSysGuard, the KDE System Guard
3 
4     Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org>
5 
6  This program is free software; you can redistribute it and/or
7  modify it under the terms of the GNU General Public License as
8  published by the Free Software Foundation; either version 2 of
9  the License or (at your option) version 3 or any later version
10  accepted by the membership of KDE e.V. (or its successor approved
11  by the membership of KDE e.V.), which shall act as a proxy
12  defined in Section 14 of version 3 of the license.
13 
14  This program is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  GNU General Public License for more details.
18 
19  You should have received a copy of the GNU General Public License
20  along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22 
23 #include <assert.h>
24 #include <string.h>
25 
26 #include <QDebug>
27 #include <QPainter>
28 
29 #include <KIconLoader>
30 #include <formatter/Formatter.h>  // from libksysguard
31 
32 #include "StyleEngine.h"
33 
34 #include "BarGraph.h"
35 
BarGraph(QWidget * parent)36 BarGraph::BarGraph( QWidget *parent )
37   : QWidget( parent )
38 {
39   bars = 0;
40   minValue = 0.0;
41   maxValue = 100.0;
42   lowerLimit = upperLimit = 0.0;
43   lowerLimitActive = upperLimitActive = false;
44 
45   normalColor = KSGRD::Style->firstForegroundColor();
46   alarmColor = KSGRD::Style->alarmColor();
47   mBackgroundColor = KSGRD::Style->backgroundColor();
48   fontSize = KSGRD::Style->fontSize();
49 
50   // Anything smaller than this does not make sense.
51   setMinimumSize( 16, 16 );
52   setSizePolicy( QSizePolicy( QSizePolicy::Expanding,
53                  QSizePolicy::Expanding ) );
54 }
55 
~BarGraph()56 BarGraph::~BarGraph()
57 {
58 }
59 
addBar(const QString & footer)60 bool BarGraph::addBar( const QString &footer )
61 {
62   samples.resize( bars + 1 );
63   samples[ bars++ ] = 0.0;
64   footers.append( footer );
65 
66   return true;
67 }
68 
removeBar(uint idx)69 bool BarGraph::removeBar( uint idx )
70 {
71   if ( idx >= bars ) {
72     qDebug() << "BarGraph::removeBar: idx " << idx << " out of range "
73                   << bars;
74     return false;
75   }
76 
77   samples.resize( --bars );
78   footers.removeAt(idx);
79   update();
80 
81   return true;
82 }
83 
updateSamples(const QVector<double> & newSamples)84 void BarGraph::updateSamples( const QVector<double> &newSamples )
85 {
86   samples = newSamples;
87   update();
88 }
89 
changeRange(double min,double max)90 void BarGraph::changeRange( double min, double max )
91 {
92   minValue = min;
93   maxValue = max;
94 }
95 
paintEvent(QPaintEvent *)96 void BarGraph::paintEvent( QPaintEvent* )
97 {
98   int w = width();
99   int h = height();
100 
101   QPainter p( this );
102 
103   p.fillRect(0,0,w, h, mBackgroundColor);
104 
105   p.setBrush( palette().color( QPalette::Light) );
106   p.setFont( QFont( p.font().family(), fontSize ) );
107   QFontMetrics fm( p.font() );
108 
109   /* Draw white line along the bottom and the right side of the
110    * widget to create a 3D like look. */
111   p.drawLine( 0, h - 1, w - 1, h - 1 );
112   p.drawLine( w - 1, 0, w - 1, h - 1 );
113 
114   p.setClipRect( 1, 1, w - 2, h - 2 );
115 
116   if ( bars > 0 ) {
117     int barWidth = ( w - 2 ) / bars;
118     uint b;
119     /* Labels are only printed underneath the bars if the labels
120      * for all bars are smaller than the bar width. If a single
121      * label does not fit no label is shown. */
122     bool showLabels = true;
123     for ( b = 0; b < bars; b++ )
124       if ( fm.boundingRect( footers[ b ] ).width() > barWidth )
125         showLabels = false;
126 
127     int barHeight;
128     if ( showLabels )
129       barHeight = h - 2 - ( 2 * fm.lineSpacing() ) - 2;
130     else
131       barHeight = h - 2;
132 
133     for ( uint b = 0; b < bars; b++ ) {
134       int topVal = int( (maxValue == 0.0) ? 0.0 :
135                    ( (float)barHeight / maxValue * ( samples[ b ] - minValue ) ) );
136       /* TODO: This widget does not handle negative values properly. */
137       if ( topVal < 0 )
138         topVal = 0;
139 
140       for ( int i = 0; i < barHeight && i < topVal; i += 2 ) {
141         if ( ( upperLimitActive && samples[ b ] > upperLimit ) ||
142              ( lowerLimitActive && samples[ b ] < lowerLimit ) )
143           p.setPen( alarmColor.lighter( static_cast<int>( 30 + ( 70.0 /
144                                       ( barHeight + 1 ) * i ) ) ) );
145         else
146           p.setPen( normalColor.lighter( static_cast<int>( 30 + ( 70.0 /
147                                       ( barHeight + 1 ) * i ) ) ) );
148         p.drawLine( b * barWidth + 3, barHeight - i, ( b + 1 ) * barWidth - 3,
149                     barHeight - i );
150       }
151 
152       if ( ( upperLimitActive && samples[ b ] > upperLimit ) ||
153            ( lowerLimitActive && samples[ b ] < lowerLimit ) )
154         p.setPen( alarmColor );
155       else
156         p.setPen( normalColor );
157 
158       if ( showLabels ) {
159         p.drawText( b * barWidth + 3, h - ( 2 * fm.lineSpacing() ) - 2,
160                     barWidth - 2 * 3, fm.lineSpacing(), Qt::AlignCenter,
161                     footers[ b ] );
162         p.drawText( b * barWidth + 3, h - fm.lineSpacing() - 2,
163                     barWidth - 2 * 3, fm.lineSpacing(), Qt::AlignCenter,
164                     KSysGuard::Formatter::formatValue( samples[b], KSysGuard::UnitNone ) );
165       }
166     }
167   }
168 
169   p.end();
170 }
171 
172 
173