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 00096 setAccessibleName(text); 00097 00098 update(); 00099 } 00100 00101 QString KCapacityBar::text() const 00102 { 00103 return d->text; 00104 } 00105 00106 void KCapacityBar::setFillFullBlocks(bool fillFullBlocks) 00107 { 00108 d->fillFullBlocks = fillFullBlocks; 00109 update(); 00110 } 00111 00112 bool KCapacityBar::fillFullBlocks() const 00113 { 00114 return d->fillFullBlocks; 00115 } 00116 00117 void KCapacityBar::setContinuous(bool continuous) 00118 { 00119 d->continuous = continuous; 00120 update(); 00121 } 00122 00123 bool KCapacityBar::continuous() const 00124 { 00125 return d->continuous; 00126 } 00127 00128 void KCapacityBar::setBarHeight(int barHeight) 00129 { 00130 // automatically convert odd values to even. This will make the bar look 00131 // better. 00132 d->barHeight = (barHeight % 2) ? barHeight + 1 : barHeight; 00133 updateGeometry(); 00134 } 00135 00136 int KCapacityBar::barHeight() const 00137 { 00138 return d->barHeight; 00139 } 00140 00141 void KCapacityBar::setHorizontalTextAlignment(Qt::Alignment horizontalTextAlignment) 00142 { 00143 Qt::Alignment alignment = horizontalTextAlignment; 00144 00145 // if the value came with any vertical alignment flag, remove it. 00146 alignment &= ~Qt::AlignTop; 00147 alignment &= ~Qt::AlignBottom; 00148 alignment &= ~Qt::AlignVCenter; 00149 00150 d->horizontalTextAlignment = alignment; 00151 update(); 00152 } 00153 00154 Qt::Alignment KCapacityBar::horizontalTextAlignment() const 00155 { 00156 return d->horizontalTextAlignment; 00157 } 00158 00159 void KCapacityBar::setDrawTextMode(DrawTextMode mode) 00160 { 00161 d->drawTextMode = mode; 00162 update(); 00163 } 00164 00165 KCapacityBar::DrawTextMode KCapacityBar::drawTextMode() const 00166 { 00167 return d->drawTextMode; 00168 } 00169 00170 void KCapacityBar::drawCapacityBar(QPainter *p, const QRect &rect) const 00171 { 00172 if (d->ce_capacityBar) 00173 { 00174 QStyleOptionProgressBar opt; 00175 opt.initFrom(this); 00176 opt.rect = rect; 00177 opt.minimum = 0; 00178 opt.maximum = 100; 00179 opt.progress = d->value; 00180 opt.text = d->text; 00181 opt.textAlignment = Qt::AlignCenter; 00182 opt.textVisible = true; 00183 style()->drawControl(d->ce_capacityBar, &opt, p, this); 00184 00185 return; 00186 } 00187 00188 p->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing); 00189 00190 p->save(); 00191 00192 QRect drawRect(rect); 00193 00194 if (d->drawTextMode == DrawTextOutline) { 00195 drawRect.setHeight(d->barHeight); 00196 } 00197 00198 QPainterPath outline; 00199 outline.moveTo(rect.left() + ROUND_MARGIN / 4 + 1, rect.top()); 00200 outline.lineTo(rect.left() + drawRect.width() - ROUND_MARGIN / 4 - 1, rect.top()); 00201 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()); 00202 outline.lineTo(rect.left() + ROUND_MARGIN / 4 + 1, drawRect.height() + rect.top()); 00203 outline.quadTo(-ROUND_MARGIN / 2 + rect.left(), drawRect.height() / 2 + rect.top(), rect.left() + ROUND_MARGIN / 4 + 1, rect.top()); 00204 const QColor fillColor = KColorScheme::shade(palette().window().color(), KColorScheme::DarkShade); 00205 p->fillPath(outline, QColor(fillColor.red(), fillColor.green(), fillColor.blue(), 50)); 00206 00207 QRadialGradient bottomGradient(QPointF(rect.width() / 2, drawRect.bottom() + 1), rect.width() / 2); 00208 bottomGradient.setColorAt(0, KColorScheme::shade(palette().window().color(), KColorScheme::LightShade)); 00209 bottomGradient.setColorAt(1, Qt::transparent); 00210 p->fillRect(QRect(rect.left(), drawRect.bottom() + rect.top(), rect.width(), 1), bottomGradient); 00211 00212 p->translate(rect.left() + 2, rect.top() + 1); 00213 00214 drawRect.setWidth(drawRect.width() - 4); 00215 drawRect.setHeight(drawRect.height() - 2); 00216 00217 QPainterPath path; 00218 path.moveTo(ROUND_MARGIN / 4, 0); 00219 path.lineTo(drawRect.width() - ROUND_MARGIN / 4, 0); 00220 path.quadTo(drawRect.width() + ROUND_MARGIN / 2, drawRect.height() / 2, drawRect.width() - ROUND_MARGIN / 4, drawRect.height()); 00221 path.lineTo(ROUND_MARGIN / 4, drawRect.height()); 00222 path.quadTo(-ROUND_MARGIN / 2, drawRect.height() / 2, ROUND_MARGIN / 4, 0); 00223 00224 QLinearGradient linearGradient(0, 0, 0, drawRect.height()); 00225 linearGradient.setColorAt(0.5, KColorScheme::shade(palette().window().color(), KColorScheme::MidShade)); 00226 linearGradient.setColorAt(1, KColorScheme::shade(palette().window().color(), KColorScheme::LightShade)); 00227 p->fillPath(path, linearGradient); 00228 00229 p->setBrush(Qt::NoBrush); 00230 p->setPen(Qt::NoPen); 00231 00232 if (d->continuous || !d->fillFullBlocks) { 00233 int start = (layoutDirection() == Qt::LeftToRight) ? -1 00234 : (drawRect.width() + 2) - (drawRect.width() + 2) * (d->value / 100.0); 00235 00236 p->setClipRect(QRect(start, 0, (drawRect.width() + 2) * (d->value / 100.0), drawRect.height()), Qt::IntersectClip); 00237 } 00238 00239 int left = (layoutDirection() == Qt::LeftToRight) ? 0 00240 : drawRect.width(); 00241 00242 int right = (layoutDirection() == Qt::LeftToRight) ? drawRect.width() 00243 : 0; 00244 00245 int roundMargin = (layoutDirection() == Qt::LeftToRight) ? ROUND_MARGIN 00246 : -ROUND_MARGIN; 00247 00248 int spacing = 2; 00249 int verticalSpacing = VERTICAL_SPACING; 00250 int slotWidth = 6; 00251 int start = roundMargin / 4; 00252 00253 QPainterPath internalBar; 00254 internalBar.moveTo(left + roundMargin / 4, 0); 00255 internalBar.lineTo(right - roundMargin / 4, 0); 00256 internalBar.quadTo(right + roundMargin / 2, drawRect.height() / 2, right - roundMargin / 4, drawRect.height()); 00257 internalBar.lineTo(left + roundMargin / 4, drawRect.height()); 00258 internalBar.quadTo(left - roundMargin / 2, drawRect.height() / 2, left + roundMargin / 4, 0); 00259 00260 QLinearGradient fillInternalBar(left, 0, right, 0); 00261 fillInternalBar.setColorAt(0, KColorScheme::shade(palette().highlight().color(), KColorScheme::MidShade)); 00262 fillInternalBar.setColorAt(0.5, KColorScheme::shade(palette().highlight().color(), KColorScheme::LightShade)); 00263 fillInternalBar.setColorAt(1, KColorScheme::shade(palette().highlight().color(), KColorScheme::MidShade)); 00264 00265 if (d->drawTextMode == KCapacityBar::DrawTextInline) { 00266 p->save(); 00267 p->setOpacity(p->opacity() * 0.7); 00268 } 00269 00270 if (!d->continuous) { 00271 int numSlots = (drawRect.width() - ROUND_MARGIN - ((slotWidth + spacing) * 2)) / (slotWidth + spacing); 00272 int stopSlot = floor((numSlots + 2) * (d->value / 100.0)); 00273 00274 int plusOffset = d->fillFullBlocks ? ((drawRect.width() - ROUND_MARGIN - ((slotWidth + spacing) * 2)) - (numSlots * (slotWidth + spacing))) / 2.0 00275 : 0; 00276 00277 if (!d->fillFullBlocks || stopSlot) { 00278 QPainterPath firstSlot; 00279 firstSlot.moveTo(left + roundMargin / 4, verticalSpacing); 00280 firstSlot.lineTo(left + slotWidth + roundMargin / 4 + plusOffset, verticalSpacing); 00281 firstSlot.lineTo(left + slotWidth + roundMargin / 4 + plusOffset, drawRect.height() - verticalSpacing); 00282 firstSlot.lineTo(left + roundMargin / 4, drawRect.height() - verticalSpacing); 00283 firstSlot.quadTo(left, drawRect.height() / 2, left + roundMargin / 4, verticalSpacing); 00284 p->fillPath(firstSlot, fillInternalBar); 00285 start += slotWidth + spacing + plusOffset; 00286 00287 bool stopped = false; 00288 for (int i = 0; i < numSlots + 1; i++) { 00289 if (d->fillFullBlocks && (i == (stopSlot + 1))) { 00290 stopped = true; 00291 break; 00292 } 00293 p->fillRect(QRect(rect.left() + start, rect.top() + verticalSpacing, slotWidth, drawRect.height() - verticalSpacing * 2), fillInternalBar); 00294 start += slotWidth + spacing; 00295 } 00296 00297 if (!d->fillFullBlocks || (!stopped && (stopSlot != (numSlots + 1)) && (stopSlot != numSlots))) { 00298 QPainterPath lastSlot; 00299 lastSlot.moveTo(start, verticalSpacing); 00300 lastSlot.lineTo(start, drawRect.height() - verticalSpacing); 00301 lastSlot.lineTo(start + slotWidth + plusOffset, drawRect.height() - verticalSpacing); 00302 lastSlot.quadTo(start + roundMargin, drawRect.height() / 2, start + slotWidth + plusOffset, verticalSpacing); 00303 lastSlot.lineTo(start, verticalSpacing); 00304 p->fillPath(lastSlot, fillInternalBar); 00305 } 00306 } 00307 } else { 00308 p->fillPath(internalBar, fillInternalBar); 00309 } 00310 00311 if (d->drawTextMode == KCapacityBar::DrawTextInline) { 00312 p->restore(); 00313 } 00314 00315 p->save(); 00316 p->setClipping(false); 00317 QRadialGradient topGradient(QPointF(rect.width() / 2, drawRect.top()), rect.width() / 2); 00318 const QColor fillTopColor = KColorScheme::shade(palette().window().color(), KColorScheme::LightShade); 00319 topGradient.setColorAt(0, QColor(fillTopColor.red(), fillTopColor.green(), fillTopColor.blue(), 127)); 00320 topGradient.setColorAt(1, Qt::transparent); 00321 p->fillRect(QRect(rect.left(), rect.top() + drawRect.top(), rect.width(), 2), topGradient); 00322 p->restore(); 00323 00324 p->save(); 00325 p->setClipRect(QRect(-1, 0, rect.width(), drawRect.height() / 2), Qt::ReplaceClip); 00326 QLinearGradient glassGradient(0, -5, 0, drawRect.height()); 00327 const QColor fillGlassColor = palette().base().color(); 00328 glassGradient.setColorAt(0, QColor(fillGlassColor.red(), fillGlassColor.green(), fillGlassColor.blue(), 255)); 00329 glassGradient.setColorAt(1, Qt::transparent); 00330 p->fillPath(internalBar, glassGradient); 00331 p->restore(); 00332 00333 p->restore(); 00334 00335 if (d->drawTextMode == KCapacityBar::DrawTextInline) { 00336 QRect rect(drawRect); 00337 rect.setHeight(rect.height() + 4); 00338 p->drawText(rect, Qt::AlignCenter, fontMetrics().elidedText(d->text, Qt::ElideRight, drawRect.width() - 2 * ROUND_MARGIN)); 00339 } else { 00340 p->drawText(rect, Qt::AlignBottom | d->horizontalTextAlignment, fontMetrics().elidedText(d->text, Qt::ElideRight, drawRect.width())); 00341 } 00342 } 00343 00344 void KCapacityBar::changeEvent(QEvent *event) 00345 { 00346 if (event->type() == QEvent::StyleChange) { 00347 d->ce_capacityBar = KStyle::customControlElement("CE_CapacityBar", this); 00348 } 00349 00350 QWidget::changeEvent(event); 00351 } 00352 00353 QSize KCapacityBar::minimumSizeHint() const 00354 { 00355 int width = (d->drawTextMode == KCapacityBar::DrawTextInline) ? 00356 fontMetrics().width(d->text) + ROUND_MARGIN * 2 : 00357 fontMetrics().width(d->text); 00358 00359 int height = (d->drawTextMode == KCapacityBar::DrawTextInline) ? 00360 qMax(fontMetrics().height(), d->barHeight) : 00361 (d->text.isEmpty() ? 0 : fontMetrics().height() + VERTICAL_SPACING * 2) + d->barHeight; 00362 00363 if (height % 2) { 00364 height++; 00365 } 00366 00367 return QSize(width, height); 00368 } 00369 00370 void KCapacityBar::paintEvent(QPaintEvent *event) 00371 { 00372 QPainter p(this); 00373 drawCapacityBar(&p, event->rect()); 00374 p.end(); 00375 } 00376 00377 #include "kcapacitybar.moc"
KDE 4.7 API Reference