libyui-qt  2.43.5
/usr/src/RPM/BUILD/libyui-qt-2.43.5/src/YQBarGraph.cc
00001 /*
00002   Copyright (C) 2000-2012 Novell, Inc
00003   This library is free software; you can redistribute it and/or modify
00004   it under the terms of the GNU Lesser General Public License as
00005   published by the Free Software Foundation; either version 2.1 of the
00006   License, or (at your option) version 3.0 of the License. This library
00007   is distributed in the hope that it will be useful, but WITHOUT ANY
00008   WARRANTY; without even the implied warranty of MERCHANTABILITY or
00009   FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
00010   License for more details. You should have received a copy of the GNU
00011   Lesser General Public License along with this library; if not, write
00012   to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
00013   Floor, Boston, MA 02110-1301 USA
00014 */
00015 
00016 
00017 /*-/
00018 
00019   File:       YQBarGraph.cc
00020 
00021   Author:     Stefan Hundhammer <sh@suse.de>
00022 
00023 /-*/
00024 
00025 
00026 #define YUILogComponent "qt-ui"
00027 #include <yui/YUILog.h>
00028 
00029 #include <algorithm>
00030 #include <qpainter.h>
00031 #include <qnamespace.h>
00032 
00033 #include "utf8.h"
00034 #include "YQUI.h"
00035 #include "YQBarGraph.h"
00036 
00037 
00038 #define YQBarGraphOuterMargin           YQWidgetMargin
00039 #define YQBarGraphLabelHorizontalMargin 1
00040 #define YQBarGraphLabelVerticalMargin   2
00041 #define YQBarGraphMinWidth              80
00042 #define YQBarGraphMinHeight             30
00043 
00044 using std::max;
00045 
00046 // a helper function, takes std::pair as a param and compares
00047 // its key (int) to the second param - true if less
00048 inline bool in_segment (pair <int, QString> seg, int cmp)
00049 {
00050     return seg.first < cmp;
00051 }
00052 
00053 YQBarGraph::YQBarGraph( YWidget * parent )
00054     : QFrame( (QWidget *) parent->widgetRep() )
00055     , YBarGraph( parent )
00056 {
00057     setWidgetRep( this );
00058 }
00059 
00060 
00061 YQBarGraph::~YQBarGraph()
00062 {
00063     // NOP
00064 }
00065 
00066 
00067 void
00068 YQBarGraph::doUpdate()
00069 {
00070     QFrame::update(); // triggers drawContents()
00071 }
00072 
00073 bool
00074 YQBarGraph::event ( QEvent *event)
00075 {
00076     if (event->type() == QEvent::ToolTip) {
00077         QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
00078 
00079         // Ook, I know this is write-only piece of code, but it basically means this:
00080         // Traverse map from the rear end, looking for the lower bound of the segment the
00081         // mouse pointer is in, using in_segment function as comparison
00082         map<int, QString>::reverse_iterator lbound =
00083             find_if( toolTips.rbegin(), toolTips.rend(), bind2nd( ptr_fun(in_segment), helpEvent->x()));
00084 
00085          if (lbound != toolTips.rend())
00086             QToolTip::showText(helpEvent->globalPos(), lbound->second );
00087      }
00088      return QWidget::event(event);
00089 
00090 }
00091 
00092 void
00093 YQBarGraph::paintEvent( QPaintEvent* paintEvent )
00094 {
00095     QFrame::paintEvent( paintEvent );
00096 
00097     QPainter painter( this );
00098 
00099     unsigned nextDefaultColor = 0;
00100     int totalWidth      = contentsRect().width()  - 2*YQBarGraphOuterMargin;
00101     int segHeight       = contentsRect().height() - 2*YQBarGraphOuterMargin;
00102     int x_off           = YQBarGraphOuterMargin;
00103     int y_off           = YQBarGraphOuterMargin;
00104     int valueTotal      = 0;
00105     QFontMetrics fm     = painter.fontMetrics();
00106 
00107     toolTips.clear();
00108 
00109     for ( int i=0; i < segments(); i++ )
00110         valueTotal += segment(i).value();
00111 
00112     if ( valueTotal == 0 ) // Avoid division by zero
00113         return;
00114 
00115     for ( int i=0; i < segments(); i++ )
00116     {
00117         const YBarGraphSegment & seg = segment(i);
00118         int segWidth = ( (long) totalWidth * seg.value() ) / valueTotal;
00119         int stringWidth = 0;
00120 
00121         if ( i == segments()-1 )
00122         {
00123             // Compensate for rounding errors:
00124             // The last segment gets all leftover pixels from the previous ones.
00125 
00126             segWidth = totalWidth - x_off + YQBarGraphOuterMargin;
00127         }
00128 
00129 
00130         //
00131         // Fill the segment
00132         //
00133 
00134         YColor segmentColor = seg.segmentColor();
00135         YColor textColor    = seg.textColor();
00136 
00137         if ( segmentColor.isUndefined() || textColor.isUndefined() )
00138         {
00139             // If any of the colors is undefined, use the next default color
00140             // for both so some contrast is ensured.
00141 
00142             segmentColor = defaultSegmentColor( nextDefaultColor   );
00143             textColor    = defaultTextColor   ( nextDefaultColor++ );
00144         }
00145 
00146         painter.setBrush( QColor( segmentColor.red(),
00147                                    segmentColor.green(),
00148                                    segmentColor.blue() ) );
00149         painter.setPen( Qt::NoPen );
00150         painter.drawRect( x_off, y_off, segWidth+2, segHeight+2 );
00151 
00152 
00153         //
00154         // Draw the label
00155         //
00156 
00157         painter.setPen( Qt::SolidLine );
00158         painter.setPen( QColor( textColor.red(),
00159                                  textColor.green(),
00160                                  textColor.blue() ) );
00161 
00162         QString txt = fromUTF8( seg.label() );
00163 
00164         if ( txt.contains( "%1" ) )
00165             txt = txt.arg( seg.value() );               // substitute variable
00166 
00167         stringWidth = fm.size(0,txt).width();
00168 
00169         // draw the text only if it fits the current segment width ...
00170         if (stringWidth < segWidth)
00171         {
00172             painter.drawText( x_off + YQBarGraphLabelHorizontalMargin,
00173                            y_off + YQBarGraphLabelVerticalMargin,
00174                            segWidth  - 2 * YQBarGraphLabelHorizontalMargin + 1,
00175                            segHeight - 2 * YQBarGraphLabelVerticalMargin   + 1,
00176                            Qt::AlignCenter, txt );
00177         }
00178 
00179         // ... but always make it available via tooltip
00180         toolTips.insert(make_pair( x_off, txt));
00181 
00182         // Prepare for the next segment
00183 
00184         x_off += segWidth;
00185     }
00186 }
00187 
00188 
00189 YColor
00190 YQBarGraph::defaultSegmentColor( unsigned index )
00191 {
00192     switch( index % 8 )
00193     {
00194         case 0: return YColor(   0,   0, 128 ); // dark blue
00195         case 1: return YColor(  64, 200, 255 ); // medium blue
00196         case 2: return YColor( 255, 255, 255 ); // white
00197         case 3: return YColor(   0, 153, 153 ); // cadet blue
00198         case 4: return YColor( 150, 255, 255 ); // cyan
00199         case 5: return YColor( 100, 100, 100 ); // medium grey
00200         case 6: return YColor(   0, 200, 100 ); // medium green
00201         case 7: return YColor(   0, 100,  76 ); // dark green
00202     }
00203 
00204     return YColor( 255, 255, 255 ); // just to make gcc happy
00205 }
00206 
00207 
00208 YColor
00209 YQBarGraph::defaultTextColor( unsigned index )
00210 {
00211     YColor black = YColor(   0,   0,   0 );
00212     YColor white = YColor( 255, 255, 255 );
00213 
00214     switch( index % 8 )
00215     {
00216         case 0: return white;
00217         case 1: return black;
00218         case 2: return black;
00219         case 3: return black;
00220         case 4: return black;
00221         case 5: return white;
00222         case 6: return black;
00223         case 7: return white;
00224     }
00225 
00226     return black; // just to make gcc happy
00227 }
00228 
00229 
00230 void
00231 YQBarGraph::setEnabled( bool enabled )
00232 {
00233     QFrame::setEnabled( enabled );
00234     YWidget::setEnabled( enabled );
00235 }
00236 
00237 
00238 int
00239 YQBarGraph::preferredWidth()
00240 {
00241     int width  = 0;
00242     QFontMetrics metrics = fontMetrics();
00243 
00244     for ( int i=0; i < segments(); i++ )
00245     {
00246         QString txt = fromUTF8( segment(i).label() );
00247 
00248         if ( txt.contains( "%1" ) )
00249             txt = txt.arg( segment(i).value() );
00250 
00251         QSize segSize = metrics.size( 0, txt );
00252         width += segSize.width();
00253     }
00254 
00255     width += 2 * YQBarGraphLabelHorizontalMargin;
00256     width += frameWidth();
00257     width += 2 * YQBarGraphOuterMargin;
00258     width  = max( width, YQBarGraphMinWidth );
00259 
00260     return width;
00261 }
00262 
00263 
00264 int
00265 YQBarGraph::preferredHeight()
00266 {
00267     int height = YQBarGraphMinHeight;
00268     QFontMetrics metrics = fontMetrics();
00269 
00270     for ( int i=0; i < segments(); i++ )
00271     {
00272         QString txt = fromUTF8( segment(i).label() );
00273 
00274         if ( txt.contains( "%1" ) )
00275             txt = txt.arg( segment(i).value() );
00276 
00277         QSize segSize = metrics.size( 0, txt );
00278         height = max( height, segSize.height() );
00279     }
00280 
00281     height += 2 * YQBarGraphLabelVerticalMargin;
00282     height += frameWidth();
00283     height += 2 * YQBarGraphOuterMargin;
00284     height  = max( height, YQBarGraphMinHeight );
00285 
00286     return height;
00287 }
00288 
00289 
00290 void
00291 YQBarGraph::setSize( int newWidth, int newHeight )
00292 {
00293     resize( newWidth, newHeight );
00294 }
00295 
00296 
00297 
00298 #include "YQBarGraph.moc"
 All Classes Functions Variables