KDEUI
kcapacitybar.cpp
Go to the documentation of this file.
00001 /* 00002 * This file is part of the KDE project 00003 * Copyright (C) 2008 Rafael Fernández López <ereslibre@kde.org> 00004 * 00005 * This library is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU Library General Public 00007 * License as published by the Free Software Foundation; either 00008 * version 2 of the License, or (at your option) any later version. 00009 * 00010 * This library is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 * Library General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Library General Public License 00016 * along with this library; see the file COPYING.LIB. If not, write to 00017 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 * Boston, MA 02110-1301, USA. 00019 */ 00020 00021 #include "kcapacitybar.h" 00022 #include <kstyle.h> 00023 00024 #include <math.h> 00025 00026 #include <QtGui/QApplication> 00027 #include <QtGui/QLabel> 00028 #include <QtGui/QStyle> 00029 #include <QtGui/QPainter> 00030 #include <QtGui/QBoxLayout> 00031 #include <QtGui/QPaintEvent> 00032 #include <QtGui/QPainterPath> 00033 #include <QtGui/QLinearGradient> 00034 #include <QtGui/QStyleOptionFrame> 00035 00036 #include <kcolorscheme.h> 00037 00038 #define ROUND_MARGIN 6 00039 #define VERTICAL_SPACING 1 00040 00041 class KCapacityBar::Private 00042 { 00043 public: 00044 Private(KCapacityBar::DrawTextMode drawTextMode) 00045 : value(0) 00046 , fillFullBlocks(true) 00047 , continuous(true) 00048 , barHeight(12) 00049 , horizontalTextAlignment(Qt::AlignCenter) 00050 , drawTextMode(drawTextMode) {} 00051 00052 ~Private() {} 00053 00054 int value; 00055 QString text; 00056 bool fillFullBlocks; 00057 bool continuous; 00058 int barHeight; 00059 Qt::Alignment horizontalTextAlignment; 00060 QStyle::ControlElement ce_capacityBar; 00061 00062 KCapacityBar::DrawTextMode drawTextMode; 00063 }; 00064 00065 KCapacityBar::KCapacityBar(KCapacityBar::DrawTextMode drawTextMode, QWidget *parent) 00066 : QWidget(parent) 00067 , d(new Private(drawTextMode)) 00068 { 00069 d->ce_capacityBar = KStyle::customControlElement("CE_CapacityBar", this); 00070 } 00071 00072 KCapacityBar::~KCapacityBar() 00073 { 00074 delete d; 00075 } 00076 00077 void KCapacityBar::setValue(int value) 00078 { 00079 d->value = value; 00080 update(); 00081 } 00082 00083 int KCapacityBar::value() const 00084 { 00085 return d->value; 00086 } 00087 00088 void KCapacityBar::setText(const QString &text) 00089 { 00090 bool updateGeom = d->text.isEmpty() || text.isEmpty(); 00091 d->text = text; 00092 if (updateGeom) { 00093 updateGeometry(); 00094 } 00095 update(); 00096 } 00097 00098 QString KCapacityBar::text() const 00099 { 00100 return d->text; 00101 } 00102 00103 void KCapacityBar::setFillFullBlocks(bool fillFullBlocks) 00104 { 00105 d->fillFullBlocks = fillFullBlocks; 00106 update(); 00107 } 00108 00109 bool KCapacityBar::fillFullBlocks() const 00110 { 00111 return d->fillFullBlocks; 00112 } 00113 00114 void KCapacityBar::setContinuous(bool continuous) 00115 { 00116 d->continuous = continuous; 00117 update(); 00118 } 00119 00120 bool KCapacityBar::continuous() const 00121 { 00122 return d->continuous; 00123 } 00124 00125 void KCapacityBar::setBarHeight(int barHeight) 00126 { 00127 // automatically convert odd values to even. This will make the bar look 00128 // better. 00129 d->barHeight = (barHeight % 2) ? barHeight + 1 : barHeight; 00130 updateGeometry(); 00131 } 00132 00133 int KCapacityBar::barHeight() const 00134 { 00135 return d->barHeight; 00136 } 00137 00138 void KCapacityBar::setHorizontalTextAlignment(Qt::Alignment horizontalTextAlignment) 00139 { 00140 Qt::Alignment alignment = horizontalTextAlignment; 00141 00142 // if the value came with any vertical alignment flag, remove it. 00143 alignment &= ~Qt::AlignTop; 00144 alignment &= ~Qt::AlignBottom; 00145 alignment &= ~Qt::AlignVCenter; 00146 00147 d->horizontalTextAlignment = alignment; 00148 update(); 00149 } 00150 00151 Qt::Alignment KCapacityBar::horizontalTextAlignment() const 00152 { 00153 return d->horizontalTextAlignment; 00154 } 00155 00156 void KCapacityBar::setDrawTextMode(DrawTextMode mode) 00157 { 00158 d->drawTextMode = mode; 00159 update(); 00160 } 00161 00162 KCapacityBar::DrawTextMode KCapacityBar::drawTextMode() const 00163 { 00164 return d->drawTextMode; 00165 } 00166 00167 void KCapacityBar::drawCapacityBar(QPainter *p, const QRect &rect) const 00168 { 00169 if (d->ce_capacityBar) 00170 { 00171 QStyleOptionProgressBar opt; 00172 opt.initFrom(this); 00173 opt.rect = rect; 00174 opt.minimum = 0; 00175 opt.maximum = 100; 00176 opt.progress = d->value; 00177 opt.text = d->text; 00178 opt.textAlignment = Qt::AlignCenter; 00179 opt.textVisible = true; 00180 style()->drawControl(d->ce_capacityBar, &opt, p, this); 00181 00182 return; 00183 } 00184 00185 p->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing); 00186 00187 p->save(); 00188 00189 QRect drawRect(rect); 00190 00191 if (d->drawTextMode == DrawTextOutline) { 00192 drawRect.setHeight(d->barHeight); 00193 } 00194 00195 QPainterPath outline; 00196 outline.moveTo(rect.left() + ROUND_MARGIN / 4 + 1, rect.top()); 00197 outline.lineTo(rect.left() + drawRect.width() - ROUND_MARGIN / 4 - 1, rect.top()); 00198 outline.quadTo(rect.left() + drawRect.width() + ROUND_MARGIN / 2, drawRect.height() / 2 + rect.top(), rect.left() + drawRect.width() - ROUND_MARGIN / 4 - 1, drawRect.height() + rect.top()); 00199 outline.lineTo(rect.left() + ROUND_MARGIN / 4 + 1, drawRect.height() + rect.top()); 00200 outline.quadTo(-ROUND_MARGIN / 2 + rect.left(), drawRect.height() / 2 + rect.top(), rect.left() + ROUND_MARGIN / 4 + 1, rect.top()); 00201 const QColor fillColor = KColorScheme::shade(palette().window().color(), KColorScheme::DarkShade); 00202 p->fillPath(outline, QColor(fillColor.red(), fillColor.green(), fillColor.blue(), 50)); 00203 00204 QRadialGradient bottomGradient(QPointF(rect.width() / 2, drawRect.bottom() + 1), rect.width() / 2); 00205 bottomGradient.setColorAt(0, KColorScheme::shade(palette().window().color(), KColorScheme::LightShade)); 00206 bottomGradient.setColorAt(1, Qt::transparent); 00207 p->fillRect(QRect(rect.left(), drawRect.bottom() + rect.top(), rect.width(), 1), bottomGradient); 00208 00209 p->translate(rect.left() + 2, rect.top() + 1); 00210 00211 drawRect.setWidth(drawRect.width() - 4); 00212 drawRect.setHeight(drawRect.height() - 2); 00213 00214 QPainterPath path; 00215 path.moveTo(ROUND_MARGIN / 4, 0); 00216 path.lineTo(drawRect.width() - ROUND_MARGIN / 4, 0); 00217 path.quadTo(drawRect.width() + ROUND_MARGIN / 2, drawRect.height() / 2, drawRect.width() - ROUND_MARGIN / 4, drawRect.height()); 00218 path.lineTo(ROUND_MARGIN / 4, drawRect.height()); 00219 path.quadTo(-ROUND_MARGIN / 2, drawRect.height() / 2, ROUND_MARGIN / 4, 0); 00220 00221 QLinearGradient linearGradient(0, 0, 0, drawRect.height()); 00222 linearGradient.setColorAt(0.5, KColorScheme::shade(palette().window().color(), KColorScheme::MidShade)); 00223 linearGradient.setColorAt(1, KColorScheme::shade(palette().window().color(), KColorScheme::LightShade)); 00224 p->fillPath(path, linearGradient); 00225 00226 p->setBrush(Qt::NoBrush); 00227 p->setPen(Qt::NoPen); 00228 00229 if (d->continuous || !d->fillFullBlocks) { 00230 int start = (layoutDirection() == Qt::LeftToRight) ? -1 00231 : (drawRect.width() + 2) - (drawRect.width() + 2) * (d->value / 100.0); 00232 00233 p->setClipRect(QRect(start, 0, (drawRect.width() + 2) * (d->value / 100.0), drawRect.height()), Qt::IntersectClip); 00234 } 00235 00236 int left = (layoutDirection() == Qt::LeftToRight) ? 0 00237 : drawRect.width(); 00238 00239 int right = (layoutDirection() == Qt::LeftToRight) ? drawRect.width() 00240 : 0; 00241 00242 int roundMargin = (layoutDirection() == Qt::LeftToRight) ? ROUND_MARGIN 00243 : -ROUND_MARGIN; 00244 00245 int spacing = 2; 00246 int verticalSpacing = VERTICAL_SPACING; 00247 int slotWidth = 6; 00248 int start = roundMargin / 4; 00249 00250 QPainterPath internalBar; 00251 internalBar.moveTo(left + roundMargin / 4, 0); 00252 internalBar.lineTo(right - roundMargin / 4, 0); 00253 internalBar.quadTo(right + roundMargin / 2, drawRect.height() / 2, right - roundMargin / 4, drawRect.height()); 00254 internalBar.lineTo(left + roundMargin / 4, drawRect.height()); 00255 internalBar.quadTo(left - roundMargin / 2, drawRect.height() / 2, left + roundMargin / 4, 0); 00256 00257 QLinearGradient fillInternalBar(left, 0, right, 0); 00258 fillInternalBar.setColorAt(0, KColorScheme::shade(palette().highlight().color(), KColorScheme::MidShade)); 00259 fillInternalBar.setColorAt(0.5, KColorScheme::shade(palette().highlight().color(), KColorScheme::LightShade)); 00260 fillInternalBar.setColorAt(1, KColorScheme::shade(palette().highlight().color(), KColorScheme::MidShade)); 00261 00262 if (d->drawTextMode == KCapacityBar::DrawTextInline) { 00263 p->save(); 00264 p->setOpacity(p->opacity() * 0.7); 00265 } 00266 00267 if (!d->continuous) { 00268 int numSlots = (drawRect.width() - ROUND_MARGIN - ((slotWidth + spacing) * 2)) / (slotWidth + spacing); 00269 int stopSlot = floor((numSlots + 2) * (d->value / 100.0)); 00270 00271 int plusOffset = d->fillFullBlocks ? ((drawRect.width() - ROUND_MARGIN - ((slotWidth + spacing) * 2)) - (numSlots * (slotWidth + spacing))) / 2.0 00272 : 0; 00273 00274 if (!d->fillFullBlocks || stopSlot) { 00275 QPainterPath firstSlot; 00276 firstSlot.moveTo(left + roundMargin / 4, verticalSpacing); 00277 firstSlot.lineTo(left + slotWidth + roundMargin / 4 + plusOffset, verticalSpacing); 00278 firstSlot.lineTo(left + slotWidth + roundMargin / 4 + plusOffset, drawRect.height() - verticalSpacing); 00279 firstSlot.lineTo(left + roundMargin / 4, drawRect.height() - verticalSpacing); 00280 firstSlot.quadTo(left, drawRect.height() / 2, left + roundMargin / 4, verticalSpacing); 00281 p->fillPath(firstSlot, fillInternalBar); 00282 start += slotWidth + spacing + plusOffset; 00283 00284 bool stopped = false; 00285 for (int i = 0; i < numSlots + 1; i++) { 00286 if (d->fillFullBlocks && (i == (stopSlot + 1))) { 00287 stopped = true; 00288 break; 00289 } 00290 p->fillRect(QRect(rect.left() + start, rect.top() + verticalSpacing, slotWidth, drawRect.height() - verticalSpacing * 2), fillInternalBar); 00291 start += slotWidth + spacing; 00292 } 00293 00294 if (!d->fillFullBlocks || (!stopped && (stopSlot != (numSlots + 1)) && (stopSlot != numSlots))) { 00295 QPainterPath lastSlot; 00296 lastSlot.moveTo(start, verticalSpacing); 00297 lastSlot.lineTo(start, drawRect.height() - verticalSpacing); 00298 lastSlot.lineTo(start + slotWidth + plusOffset, drawRect.height() - verticalSpacing); 00299 lastSlot.quadTo(start + roundMargin, drawRect.height() / 2, start + slotWidth + plusOffset, verticalSpacing); 00300 lastSlot.lineTo(start, verticalSpacing); 00301 p->fillPath(lastSlot, fillInternalBar); 00302 } 00303 } 00304 } else { 00305 p->fillPath(internalBar, fillInternalBar); 00306 } 00307 00308 if (d->drawTextMode == KCapacityBar::DrawTextInline) { 00309 p->restore(); 00310 } 00311 00312 p->save(); 00313 p->setClipping(false); 00314 QRadialGradient topGradient(QPointF(rect.width() / 2, drawRect.top()), rect.width() / 2); 00315 const QColor fillTopColor = KColorScheme::shade(palette().window().color(), KColorScheme::LightShade); 00316 topGradient.setColorAt(0, QColor(fillTopColor.red(), fillTopColor.green(), fillTopColor.blue(), 127)); 00317 topGradient.setColorAt(1, Qt::transparent); 00318 p->fillRect(QRect(rect.left(), rect.top() + drawRect.top(), rect.width(), 2), topGradient); 00319 p->restore(); 00320 00321 p->save(); 00322 p->setClipRect(QRect(-1, 0, rect.width(), drawRect.height() / 2), Qt::ReplaceClip); 00323 QLinearGradient glassGradient(0, -5, 0, drawRect.height()); 00324 const QColor fillGlassColor = palette().base().color(); 00325 glassGradient.setColorAt(0, QColor(fillGlassColor.red(), fillGlassColor.green(), fillGlassColor.blue(), 255)); 00326 glassGradient.setColorAt(1, Qt::transparent); 00327 p->fillPath(internalBar, glassGradient); 00328 p->restore(); 00329 00330 p->restore(); 00331 00332 if (d->drawTextMode == KCapacityBar::DrawTextInline) { 00333 QRect rect(drawRect); 00334 rect.setHeight(rect.height() + 4); 00335 p->drawText(rect, Qt::AlignCenter, fontMetrics().elidedText(d->text, Qt::ElideRight, drawRect.width() - 2 * ROUND_MARGIN)); 00336 } else { 00337 p->drawText(rect, Qt::AlignBottom | d->horizontalTextAlignment, fontMetrics().elidedText(d->text, Qt::ElideRight, drawRect.width())); 00338 } 00339 } 00340 00341 void KCapacityBar::changeEvent(QEvent *event) 00342 { 00343 if (event->type() == QEvent::StyleChange) { 00344 d->ce_capacityBar = KStyle::customControlElement("CE_CapacityBar", this); 00345 } 00346 00347 QWidget::changeEvent(event); 00348 } 00349 00350 QSize KCapacityBar::minimumSizeHint() const 00351 { 00352 int width = (d->drawTextMode == KCapacityBar::DrawTextInline) ? 00353 fontMetrics().width(d->text) + ROUND_MARGIN * 2 : 00354 fontMetrics().width(d->text); 00355 00356 int height = (d->drawTextMode == KCapacityBar::DrawTextInline) ? 00357 qMax(fontMetrics().height(), d->barHeight) : 00358 (d->text.isEmpty() ? 0 : fontMetrics().height() + VERTICAL_SPACING * 2) + d->barHeight; 00359 00360 if (height % 2) { 00361 height++; 00362 } 00363 00364 return QSize(width, height); 00365 } 00366 00367 void KCapacityBar::paintEvent(QPaintEvent *event) 00368 { 00369 QPainter p(this); 00370 drawCapacityBar(&p, event->rect()); 00371 p.end(); 00372 } 00373 00374 #include "kcapacitybar.moc"
KDE 4.6 API Reference