| Home · All Classes · Main Classes · Deprecated |
00001 /*************************************************************************** 00002 ** 00003 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). 00004 ** All rights reserved. 00005 ** Contact: Nokia Corporation (directui@nokia.com) 00006 ** 00007 ** This file is part of libmeegotouch. 00008 ** 00009 ** If you have questions regarding the use of this file, please contact 00010 ** Nokia at directui@nokia.com. 00011 ** 00012 ** This library is free software; you can redistribute it and/or 00013 ** modify it under the terms of the GNU Lesser General Public 00014 ** License version 2.1 as published by the Free Software Foundation 00015 ** and appearing in the file LICENSE.LGPL included in the packaging 00016 ** of this file. 00017 ** 00018 ****************************************************************************/ 00019 00020 #include "mbuttonview.h" 00021 #include "mbuttonview_p.h" 00022 00023 #include <QPainter> 00024 #include <QGraphicsSceneMouseEvent> 00025 #include <QFontMetricsF> 00026 #include <QPixmap> 00027 #include <QIcon> 00028 #include <QTimer> 00029 00030 #include "mbutton.h" 00031 #include "mfeedback.h" 00032 #include "mtheme.h" 00033 #include "mscalableimage.h" 00034 #include "mviewcreator.h" 00035 #include "mscenemanager.h" 00036 #include "mlabel.h" 00037 #include "mdebug.h" 00038 #include "mtimestamp.h" 00039 #include "mviewconstants.h" 00040 00041 MButtonViewPrivate::MButtonViewPrivate() 00042 : icon(0), toggledIcon(0), label(NULL), styleModeChangeTimer(NULL), 00043 iconOrigin(IconOriginUndefined), toggledIconOrigin(IconOriginUndefined), 00044 queuedStyleModeChange(false) 00045 { 00046 } 00047 00048 MButtonViewPrivate::Icon::Icon() 00049 { 00050 pixmap = 0; 00051 origin = IconOriginUndefined; 00052 } 00053 00054 MButtonViewPrivate::Icon::~Icon() 00055 { 00056 switch(origin) { 00057 case IconOriginFromModelIconId: 00058 case IconOriginFromStyleIconId: 00059 MTheme::releasePixmap(pixmap); 00060 break; 00061 00062 case IconOriginFromModelQIcon: 00063 delete pixmap; 00064 break; 00065 00066 case IconOriginUndefined: 00067 default: 00068 break; 00069 } 00070 00071 pixmap = 0; 00072 origin = IconOriginUndefined; 00073 id.clear(); 00074 theme.clear(); 00075 } 00076 00077 int MButtonViewPrivate::pressTimeout() const 00078 { 00079 Q_Q(const MButtonView); 00080 00081 return q->style()->pressTimeout(); 00082 } 00083 00084 void MButtonViewPrivate::freeIcons() 00085 { 00086 if (icon) { 00087 delete icon; 00088 icon = 0; 00089 } 00090 00091 if (toggledIcon) { 00092 delete toggledIcon; 00093 toggledIcon = 0; 00094 } 00095 } 00096 00097 MButtonViewPrivate::~MButtonViewPrivate() 00098 { 00099 freeIcons(); 00100 } 00101 00102 // As the condition of text color and background change for button 00103 bool MButtonViewPrivate::toggleState() const 00104 { 00105 Q_Q(const MButtonView); 00106 if (q->model()->checkable()) { 00107 bool state = (!q->model()->checked() && q->model()->down()) 00108 || (q->model()->checked() && !q->model()->down()); 00109 return state; 00110 } else 00111 return q->model()->down(); 00112 } 00113 00114 void MButtonViewPrivate::_q_applyQueuedStyleModeChange() 00115 { 00116 Q_Q(MButtonView); 00117 00118 if (queuedStyleModeChange) { 00119 queuedStyleModeChange = false; 00120 q->applyStyle(); 00121 } 00122 } 00123 00124 void MButtonViewPrivate::refreshStyleMode() 00125 { 00126 Q_Q(MButtonView); 00127 00128 if (controller->isEnabled()) { 00129 if (q->model()->down()) { 00130 if (styleModeChangeTimer->isActive()) { 00131 styleModeChangeTimer->start(pressTimeout()); 00132 return; 00133 } 00134 styleModeChangeTimer->start(pressTimeout()); 00135 q->style().setModePressed(); 00136 } else if (q->model()->checked()) { 00137 q->style().setModeSelected(); 00138 } else { 00139 if (styleModeChangeTimer->isActive()) { 00140 queuedStyleModeChange = true; 00141 return; 00142 } 00143 q->style().setModeDefault(); 00144 } 00145 } else { 00146 styleModeChangeTimer->stop(); 00147 q->style().setModeDisabled(); 00148 } 00149 00150 label->setAlignment(q->style()->horizontalTextAlign() | q->style()->verticalTextAlign()); 00151 label->setFont(q->style()->font()); 00152 label->setColor(q->style()->textColor()); 00153 00154 updateIcon(); 00155 updateToggledIcon(); 00156 00157 calcIconTextRects(); 00158 } 00159 00160 QSizeF MButtonViewPrivate::maxTextSize() const 00161 { 00162 Q_Q(const MButtonView); 00163 00164 const QFontMetrics fm(q->style()->font()); 00165 00166 QString text = q->model()->text(); 00167 const QChar multiLengthSeparator(0x9c, 0); 00168 const int index = text.indexOf(multiLengthSeparator); 00169 if (index >= 0) { 00170 text = text.left(index); 00171 } 00172 00173 return QSizeF(fm.width(text), fm.height()); 00174 } 00175 00176 void MButtonViewPrivate::calcIconTextRects() 00177 { 00178 Q_Q(const MButtonView); 00179 00180 //total horizontal and vertical text margins 00181 int hTextMargin = q->style()->textMarginLeft() + q->style()->textMarginRight(); 00182 int vTextMargin = q->style()->textMarginTop() + q->style()->textMarginBottom(); 00183 00184 //total horizontal and vertical padding 00185 int hPadding = q->style()->paddingLeft() + q->style()->paddingRight(); 00186 int vPadding = q->style()->paddingTop() + q->style()->paddingBottom(); 00187 00188 //area for the content (icon and text) 00189 QRectF contentRect(q->style()->paddingLeft(), q->style()->paddingTop(), 00190 q->size().width() - hPadding, 00191 q->size().height() - vPadding); 00192 00193 //text rect when there is no icon 00194 QRectF textRect(contentRect.left() + q->style()->textMarginLeft(), 00195 contentRect.top() + q->style()->textMarginTop(), 00196 contentRect.width() - hTextMargin, 00197 contentRect.height() - vTextMargin); 00198 00199 QSizeF textSize = maxTextSize(); 00200 00201 //icon visible and valid? 00202 if (q->model()->iconVisible() && (icon || toggledIcon)) { 00203 00204 int iconWidth = q->style()->iconSize().width(); 00205 int iconHeight = q->style()->iconSize().height(); 00206 00207 QSizeF iconSize(iconWidth, iconHeight); 00208 QPointF iconPosition(0, 0); 00209 00210 //text visible and valid? 00211 if (q->model()->textVisible() && !q->model()->text().isEmpty()) { 00212 textSize.setWidth(qMin(textSize.width(), contentRect.width() - iconWidth - hTextMargin)); 00213 switch (q->style()->iconAlign()) { 00214 //icon on left and text on right 00215 case Qt::AlignLeft: { 00216 if (q->style()->horizontalTextAlign() == Qt::AlignHCenter) 00217 iconPosition.setX(contentRect.center().x() - iconWidth - (textSize.width() / 2)); 00218 else if (q->style()->horizontalTextAlign() == Qt::AlignRight) 00219 iconPosition.setX(contentRect.right() - textSize.width() - iconWidth - hTextMargin); 00220 else if (q->style()->horizontalTextAlign() == Qt::AlignLeft) 00221 iconPosition.setX(contentRect.left()); 00222 00223 iconPosition.setY(contentRect.center().y() - (iconHeight / 2)); 00224 textRect.setX(contentRect.left() + q->style()->textMarginLeft() + iconWidth); 00225 textRect.setWidth(contentRect.width() - iconWidth - hTextMargin); 00226 break; 00227 } 00228 00229 //icon on right and text on left 00230 case Qt::AlignRight: { 00231 if (q->style()->horizontalTextAlign() == Qt::AlignHCenter) 00232 iconPosition.setX(contentRect.center().x() + (textSize.width() / 2)); 00233 else if (q->style()->horizontalTextAlign() == Qt::AlignRight) 00234 iconPosition.setX(contentRect.right() - iconWidth); 00235 else if (q->style()->horizontalTextAlign() == Qt::AlignLeft) 00236 iconPosition.setX(contentRect.left() + textSize.width() + hTextMargin); 00237 00238 iconPosition.setY(contentRect.center().y() - (iconHeight / 2)); 00239 textRect.setWidth(contentRect.width() - iconWidth - hTextMargin); 00240 break; 00241 } 00242 00243 //icon on bottom and text on top 00244 case Qt::AlignBottom: { 00245 iconPosition = QPointF(contentRect.center().x() - (iconWidth / 2), contentRect.bottom() - iconHeight); 00246 textRect.setHeight(contentRect.height() - iconHeight - vTextMargin); 00247 break; 00248 } 00249 00250 //icon on top and text on bottom 00251 default: { 00252 iconPosition = QPointF(contentRect.center().x() - (iconWidth / 2), contentRect.top()); 00253 textRect.setY(iconRect.bottom() + q->style()->textMarginTop()); 00254 textRect.setHeight(contentRect.height() - iconHeight - vTextMargin); 00255 break; 00256 } 00257 } 00258 } 00259 // no text 00260 else { 00261 //icon on center 00262 iconPosition = QPointF(contentRect.center().x() - (iconWidth / 2), contentRect.center().y() - (iconHeight / 2)); 00263 } 00264 00265 iconRect = QRectF(iconPosition, iconSize); 00266 } 00267 00268 //adjust label with button margins 00269 if (controller->layoutDirection() == Qt::LeftToRight) 00270 label->setGeometry(textRect.translated(q->marginLeft(), q->marginTop())); 00271 else 00272 label->setGeometry(textRect.translated(q->marginRight(), q->marginTop())); 00273 } 00274 00275 bool MButtonViewPrivate::isCurrentIconObsolete(const QString &newIconId) const 00276 { 00277 Q_Q(const MButtonView); 00278 bool result = false; 00279 00280 if (icon) { 00281 result = icon->id != newIconId // it's a different icon 00282 || icon->theme != MTheme::currentTheme() // current icon is from a previous theme. 00283 // In the new theme the id might point 00284 // to a different graphical asset. 00285 || icon->pixmap->size() != q->style()->iconSize(); // icon has changed its size 00286 } else { 00287 // We don't even have an icon to compare with. 00288 result = true; 00289 } 00290 00291 return result; 00292 } 00293 00294 void MButtonViewPrivate::updateIcon(Icon **iconPtr, 00295 QIcon::Mode mode, const QString &iconIdFromModel, 00296 const QString &iconIdFromStyle) 00297 { 00298 Q_Q(MButtonView); 00299 Icon *icon = *iconPtr; 00300 00301 /* 00302 Fallback order for chosing where to take the icon from: 00303 1 - MButtonModel::icon(), a QIcon 00304 2 - MButtonModel::[toggled]iconID(), a QString 00305 3 - MButtonStyle::[toggled]iconId(), a QString 00306 4 - No icon at all 00307 */ 00308 00309 /* 00310 We only reload an icon if it has really changed. 00311 */ 00312 00313 if (!q->model()->icon().isNull()) { 00314 00315 if (icon) 00316 delete icon; 00317 00318 icon = new Icon; 00319 *iconPtr = icon; 00320 00321 icon->pixmap = new QPixmap(q->model()->icon().pixmap(q->style()->iconSize(), mode)); 00322 icon->origin = IconOriginFromModelQIcon; 00323 00324 } else if (!iconIdFromModel.isEmpty() && isCurrentIconObsolete(iconIdFromModel)) { 00325 00326 if (icon) 00327 delete icon; 00328 00329 icon = new Icon; 00330 *iconPtr = icon; 00331 00332 icon->pixmap = MTheme::pixmap(iconIdFromModel, q->style()->iconSize()); 00333 icon->origin = IconOriginFromModelIconId; 00334 icon->id = iconIdFromModel; 00335 icon->theme = MTheme::currentTheme(); 00336 00337 } else if (!iconIdFromStyle.isEmpty() && isCurrentIconObsolete(iconIdFromStyle)) { 00338 00339 if (icon) 00340 delete icon; 00341 00342 icon = new Icon; 00343 *iconPtr = icon; 00344 00345 icon->pixmap = MTheme::pixmap(iconIdFromStyle, q->style()->iconSize()); 00346 icon->origin = IconOriginFromStyleIconId; 00347 icon->id = iconIdFromStyle; 00348 icon->theme = MTheme::currentTheme(); 00349 00350 } else if (iconIdFromModel.isEmpty() && iconIdFromStyle.isEmpty()) { 00351 delete icon; 00352 icon = NULL; 00353 *iconPtr = icon; 00354 } 00355 } 00356 00357 void MButtonViewPrivate::updateIcon() 00358 { 00359 Q_Q(MButtonView); 00360 updateIcon(&icon, QIcon::Normal, q->model()->iconID(), q->style()->iconId()); 00361 } 00362 00363 void MButtonViewPrivate::updateToggledIcon() 00364 { 00365 Q_Q(MButtonView); 00366 updateIcon(&toggledIcon, QIcon::Selected, q->model()->toggledIconID(), q->style()->toggledIconId()); 00367 } 00368 00369 MButtonView::MButtonView(MButton *controller) : 00370 MWidgetView(* new MButtonViewPrivate, controller) 00371 { 00372 Q_D(MButtonView); 00373 d->label = new MLabel(controller); 00374 d->label->setParentItem(controller); 00375 d->label->setTextElide(true); 00376 d->label->setObjectName("ButtonLabel"); 00377 d->label->setMinimumSize(0,0); 00378 00379 d->styleModeChangeTimer = new QTimer(this); 00380 d->styleModeChangeTimer->setSingleShot(true); 00381 connect(d->styleModeChangeTimer, SIGNAL(timeout()), SLOT(_q_applyQueuedStyleModeChange())); 00382 } 00383 00384 MButtonView::MButtonView(MButtonViewPrivate &dd, MButton *controller) : 00385 MWidgetView(dd, controller) 00386 { 00387 Q_D(MButtonView); 00388 d->label = new MLabel(controller); 00389 d->label->setParentItem(controller); 00390 d->label->setTextElide(true); 00391 d->label->setObjectName("ButtonLabel"); 00392 d->label->setMinimumSize(0,0); 00393 00394 d->styleModeChangeTimer = new QTimer(this); 00395 d->styleModeChangeTimer->setSingleShot(true); 00396 connect(d->styleModeChangeTimer, SIGNAL(timeout()), SLOT(_q_applyQueuedStyleModeChange())); 00397 } 00398 00399 MButtonView::~MButtonView() 00400 { 00401 Q_D(MButtonView); 00402 if (d->label) { 00403 delete d->label; 00404 d->label = 0; 00405 } 00406 } 00407 00408 void MButtonView::resizeEvent(QGraphicsSceneResizeEvent *event) 00409 { 00410 Q_D(MButtonView); 00411 00412 MWidgetView::resizeEvent(event); 00413 00414 d->calcIconTextRects(); 00415 } 00416 00417 void MButtonView::drawContents(QPainter *painter, const QStyleOptionGraphicsItem *option) const 00418 { 00419 Q_UNUSED(option); 00420 00421 Q_D(const MButtonView); 00422 mTimestamp("MButtonView", QString("start text=%1").arg(model()->text())); 00423 drawIcon(painter, d->iconRect); 00424 mTimestamp("MButtonView", QString("end text=%1").arg(model()->text())); 00425 } 00426 00427 void MButtonView::drawIcon(QPainter *painter, const QRectF &iconRect) const 00428 { 00429 if (model()->iconVisible()) { 00430 Q_D(const MButtonView); 00431 00432 bool toggleState = d->toggleState(); 00433 00434 const QPixmap *pixmap = NULL; 00435 if (toggleState && d->toggledIcon) 00436 pixmap = d->toggledIcon->pixmap; 00437 else if (d->icon) 00438 pixmap = d->icon->pixmap; 00439 00440 if (pixmap) 00441 painter->drawPixmap(iconRect, *pixmap, QRectF(pixmap->rect())); 00442 } 00443 } 00444 00445 /*MLabel* MButtonView::label() 00446 { 00447 Q_D(const MButtonView); 00448 return d->label; 00449 }*/ 00450 00451 void MButtonView::applyStyle() 00452 { 00453 Q_D(MButtonView); 00454 00455 MWidgetView::applyStyle(); 00456 00457 d->refreshStyleMode(); 00458 00459 update(); 00460 } 00461 00462 void MButtonView::mousePressEvent(QGraphicsSceneMouseEvent *event) 00463 { 00464 Q_UNUSED(event); 00465 00466 if (model()->down()) { 00467 return; 00468 } 00469 model()->setDown(true); 00470 00471 style()->pressFeedback().play(); 00472 } 00473 00474 void MButtonView::mouseMoveEvent(QGraphicsSceneMouseEvent *event) 00475 { 00476 Q_D(MButtonView); 00477 00478 QPointF touch = event->scenePos(); 00479 QRectF rect = d->controller->sceneBoundingRect(); 00480 rect.adjust(-M_RELEASE_MISS_DELTA, -M_RELEASE_MISS_DELTA, 00481 M_RELEASE_MISS_DELTA, M_RELEASE_MISS_DELTA); 00482 00483 if (rect.contains(touch)) { 00484 if (!model()->down()) { 00485 model()->setDown(true); 00486 style()->pressFeedback().play(); 00487 } 00488 } else { 00489 if (model()->down()) { 00490 model()->setDown(false); 00491 style()->cancelFeedback().play(); 00492 } 00493 } 00494 00495 } 00496 00497 void MButtonView::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) 00498 { 00499 Q_D(MButtonView); 00500 00501 if (!model()->down()) { 00502 return; 00503 } 00504 model()->setDown(false); 00505 00506 style()->releaseFeedback().play(); 00507 00508 QPointF touch = event->scenePos(); 00509 QRectF rect = d->controller->sceneBoundingRect(); 00510 rect.adjust(-M_RELEASE_MISS_DELTA, -M_RELEASE_MISS_DELTA, 00511 M_RELEASE_MISS_DELTA, M_RELEASE_MISS_DELTA); 00512 if (rect.contains(touch)) 00513 model()->click(); 00514 } 00515 00516 void MButtonView::cancelEvent(MCancelEvent *event) 00517 { 00518 Q_UNUSED(event); 00519 00520 if (!model()->down()) { 00521 return; 00522 } 00523 00524 style()->cancelFeedback().play(); 00525 00526 model()->setDown(false); 00527 } 00528 00529 void MButtonView::updateData(const QList<const char *>& modifications) 00530 { 00531 Q_D(MButtonView); 00532 00533 MWidgetView::updateData(modifications); 00534 const char *member; 00535 00536 bool mustCalcIconTextRects = false; 00537 bool mustUpdateIcon = false; 00538 bool mustUpdateToggledIcon = false; 00539 00540 foreach(member, modifications) { 00541 if (member == MButtonModel::Text) { 00542 d->label->setText(model()->text()); 00543 mustCalcIconTextRects = true; 00544 } else if (member == MButtonModel::TextVisible) { 00545 d->label->setVisible(model()->textVisible()); 00546 mustCalcIconTextRects = true; 00547 } else if (member == MButtonModel::IconID) { 00548 mustUpdateIcon = true; 00549 mustCalcIconTextRects = true; 00550 } else if (member == MButtonModel::ToggledIconID) { 00551 mustUpdateToggledIcon = true; 00552 mustCalcIconTextRects = true; 00553 } else if (member == MButtonModel::Icon) { 00554 mustUpdateIcon = true; 00555 mustUpdateToggledIcon = true; 00556 mustCalcIconTextRects = true; 00557 } else if (member == MButtonModel::IconVisible) { 00558 mustCalcIconTextRects = true; 00559 } else if (member == MButtonModel::Down || member == MButtonModel::Checked || 00560 member == MButtonModel::Checkable) { 00561 d->refreshStyleMode(); 00562 } 00563 } 00564 00565 if (mustUpdateIcon) { 00566 d->updateIcon(); 00567 } 00568 00569 if (mustUpdateToggledIcon) { 00570 d->updateToggledIcon(); 00571 } 00572 00573 if (mustCalcIconTextRects) { 00574 d->calcIconTextRects(); 00575 } 00576 00577 update(); 00578 } 00579 00580 void MButtonView::setupModel() 00581 { 00582 Q_D(MButtonView); 00583 00584 MWidgetView::setupModel(); 00585 QList<const char *> members; 00586 if (model()->icon().isNull()) 00587 members << MButtonModel::IconID; 00588 else 00589 members << MButtonModel::Icon; 00590 if (!model()->toggledIconID().isEmpty()) 00591 members << MButtonModel::ToggledIconID; 00592 00593 updateData(members); 00594 00595 d->label->setText(model()->text()); 00596 d->label->setVisible(model()->textVisible()); 00597 00598 d->calcIconTextRects(); 00599 00600 update(); 00601 } 00602 00603 QSizeF MButtonView::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const 00604 { 00605 Q_D(const MButtonView); 00606 00607 if (which == Qt::MinimumSize || which == Qt::MaximumSize) 00608 return MWidgetView::sizeHint(which, constraint); 00609 00610 QSizeF iconSize(0, 0); 00611 if (model()->iconVisible() && d->icon) 00612 iconSize = d->icon->pixmap->size(); 00613 00614 QSizeF textSize(0, 0); 00615 if (model()->textVisible() && !model()->text().isEmpty()) { 00616 textSize = d->maxTextSize(); 00617 textSize += QSizeF(style()->textMarginLeft() + style()->textMarginRight(), style()->textMarginTop() + style()->textMarginBottom()); 00618 } 00619 00620 qreal width = 0, height = 0; 00621 if (style()->iconAlign() == Qt::AlignTop || style()->iconAlign() == Qt::AlignBottom) { 00622 width = qMax(iconSize.width(), textSize.width()); 00623 height = iconSize.height() + textSize.height(); 00624 } else { 00625 width = iconSize.width() + textSize.width(); 00626 height = qMax(iconSize.height(), textSize.height()); 00627 } 00628 00629 return QSizeF(width + style()->paddingLeft() + style()->paddingRight(), height + style()->paddingTop() + style()->paddingBottom()); 00630 } 00631 00632 M_REGISTER_VIEW_NEW(MButtonView, MButton) 00633 00634 #include "moc_mbuttonview.cpp"
| Copyright © 2010 Nokia Corporation | Generated on Thu Nov 4 2010 18:14:20 (PDT) Doxygen 1.7.1 |
MeeGo Touch |