--- a/src/hbwidgets/itemviews/hbabstractviewitem.cpp Tue Jul 06 14:36:53 2010 +0300
+++ b/src/hbwidgets/itemviews/hbabstractviewitem.cpp Wed Aug 18 10:05:37 2010 +0300
@@ -36,6 +36,7 @@
#include <hbwidgetfeedback.h>
#include <hbtapgesture.h>
#include <hbnamespace_p.h>
+#include <hbevent.h>
#include <QPersistentModelIndex>
#include <QGraphicsLayout>
@@ -44,10 +45,15 @@
#include <QEvent>
#include <QTimer>
#include <QGraphicsScene>
+
+#include <QPixmap>
+#include <QPainter>
#include <QDebug>
+#include <QChildEvent>
#include <QGesture>
#include <QGestureEvent>
+#include <QGraphicsSceneEvent>
const QString KDefaultLayoutOption = "default";
const int HbAbstractViewItemShared::ViewItemDeferredDeleteEvent = QEvent::registerEventType();
@@ -77,6 +83,8 @@
position selection areas etc.) this information can be supplied to transient state model. Transient state model is maintained
internally by abstract item view.
+ If item's pixmap cache is enabled derived class should call updatePixmapCache() when ever visual appearance of the item or its children is
+ changed. For more information about enabling the pixmap cache see HbAbstractItemView::setItemPixmapCacheEnabled().
\primitives
\primitive{background} HbIconItem representing the item background. This primitive exists in cases the model's Qt::BackgroundRole returns HbIcon or QBrush for this item.
@@ -183,11 +191,28 @@
mPressedItem->pressStateChanged(true, mAnimatePress);
}
+void HbAbstractViewItemShared::disablePixmapCaches()
+{
+ mLowGraphicsMemory = true;
+ foreach (HbAbstractViewItem *item, mCloneItems) {
+ item->update();
+ }
+}
+
+void HbAbstractViewItemShared::enablePixmapCaches()
+{
+ mLowGraphicsMemory = false;
+ foreach (HbAbstractViewItem *item, mCloneItems) {
+ item->update();
+ }
+}
+
void HbAbstractViewItemPrivate::init()
{
Q_Q(HbAbstractViewItem);
q->setProperty("state", "normal");
+ q->setFlag(QGraphicsItem::ItemHasNoContents, false);
if (isPrototype()) {
q->setFocusPolicy(Qt::ClickFocus);
@@ -200,6 +225,8 @@
q->setFocusPolicy(mSharedData->mPrototype->focusPolicy());
mSharedData->mCloneItems.append(q);
+
+ mFrontPixmapPainter = new HbViewItemPixmapPainter(1000, q);
}
}
@@ -278,6 +305,7 @@
if (gesture->tapStyleHint() == HbTapGesture::TapAndHold
&& mSharedData->mItemView
&& mSharedData->mItemView->longPressEnabled()) {
+ q->scene()->setProperty(HbPrivate::OverridingGesture.latin1(),QVariant());
setPressed(false, true);
QPointer<HbAbstractViewItem> item = q;
emit item->longPressed(position);
@@ -374,6 +402,134 @@
}
}
+void HbAbstractViewItemPrivate::paintItems(QPainter *painter, QStyleOptionGraphicsItem *option, QGraphicsItem *startItem, QGraphicsItem *endItem)
+{
+ Q_Q(HbAbstractViewItem);
+
+ mInPaintItems = true;
+
+ bool itemPainted = false;
+
+ bool startItemFound = false;
+ if (!startItem) {
+ startItemFound = true;
+ }
+
+ foreach (QGraphicsItem *child, q->childItems()) {
+ if (!startItemFound) {
+ if (child == startItem) {
+ startItemFound = true;
+ }
+ continue;
+ } else if (child == endItem) {
+ break;
+ }
+
+ if (!child->isVisible() || child == mNonCachableItem || child == mFrontPixmapPainter || child == mBackPixmapPainter) {
+ continue;
+ }
+
+ if (!itemPainted && child->zValue() >= 0) {
+ painter->save();
+ option->exposedRect = q->boundingRect();
+ q->paint(painter, option, 0);
+ painter->restore();
+ itemPainted = true;
+ }
+
+ painter->save();
+ if (child == mFrame) {
+ painter->setCompositionMode(QPainter::CompositionMode_Source);
+ }
+
+ painter->translate(child->pos());
+
+ option->exposedRect = child->boundingRect();
+ child->paint(painter, option, 0);
+
+ painter->restore();
+ }
+
+ mInPaintItems = false;
+}
+
+void HbAbstractViewItemPrivate::setChildFlags(QGraphicsItem *child, bool pixmapCacheEnabled)
+{
+ Q_Q(HbAbstractViewItem);
+
+ if (child) {
+ QGraphicsItem::GraphicsItemFlags itemFlags = child->flags();
+ if (pixmapCacheEnabled) {
+ itemFlags |= QGraphicsItem::ItemHasNoContents;
+ itemFlags |= QGraphicsItem::ItemIgnoresParentOpacity;
+ }
+ else {
+ itemFlags &= ~QGraphicsItem::ItemHasNoContents;
+ itemFlags &= ~QGraphicsItem::ItemIgnoresParentOpacity;
+ }
+ child->setFlags(itemFlags);
+ } else {
+ foreach (QGraphicsItem *child, q->childItems()) {
+ if (child == mNonCachableItem || child == mFrontPixmapPainter || child == mBackPixmapPainter) {
+ continue;
+ }
+
+ QGraphicsItem::GraphicsItemFlags itemFlags = child->flags();
+ if (pixmapCacheEnabled) {
+ itemFlags |= QGraphicsItem::ItemHasNoContents;
+ itemFlags |= QGraphicsItem::ItemIgnoresParentOpacity;
+ }
+ else {
+ itemFlags &= ~QGraphicsItem::ItemHasNoContents;
+ itemFlags &= ~QGraphicsItem::ItemIgnoresParentOpacity;
+ }
+ child->setFlags(itemFlags);
+ }
+ }
+}
+
+void HbAbstractViewItemPrivate::updatePixmap(QPixmap *pixmap,
+ QPainter *painter,
+ const QTransform &itemToPixmapTransform,
+ const QStyleOptionGraphicsItem *option,
+ QGraphicsItem *startItem,
+ QGraphicsItem *endItem)
+{
+ pixmap->fill(Qt::transparent);
+
+ QPainter pixmapPainter;
+ pixmapPainter.begin(pixmap);
+
+ pixmapPainter.setWorldTransform(itemToPixmapTransform, true);
+
+ pixmapPainter.setRenderHints(pixmapPainter.renderHints(), false);
+ pixmapPainter.setRenderHints(painter->renderHints());
+
+ // Draw items on the pixmap
+ QStyleOptionGraphicsItem pixmapOption(*option);
+ paintItems(&pixmapPainter, &pixmapOption, startItem, endItem);
+}
+
+void HbAbstractViewItemPrivate::releasePixmaps()
+{
+ if (mFrontCachePixmap) {
+ delete mFrontCachePixmap;
+ mFrontCachePixmap = 0;
+ }
+
+ if (mFrontPixmapPainter) {
+ mFrontPixmapPainter->setPixmap(0);
+ }
+
+ if (mBackCachePixmap) {
+ delete mBackCachePixmap;
+ mBackCachePixmap = 0;
+ }
+
+ if (mBackPixmapPainter) {
+ mBackPixmapPainter->setPixmap(0);
+ }
+}
/*!
Constructs an abstract view item with the given parent.
@@ -431,6 +587,8 @@
if (d && !d->isPrototype()) {
sd->mCloneItems.removeOne(this);
}
+ delete d->mFrontCachePixmap;
+ delete d->mBackCachePixmap;
}
/*!
@@ -490,10 +648,7 @@
{
Q_D( const HbAbstractViewItem );
QHash<QString,QVariant> state;
-
- if (d->mFocused) {
- state.insert("focused", d->mFocused);
- }
+
if (d->mCheckState != Qt::Unchecked) {
state.insert("checkState", d->mCheckState);
}
@@ -507,8 +662,10 @@
void HbAbstractViewItem::setTransientState(const QHash<QString, QVariant> &state)
{
Q_D( HbAbstractViewItem );
- d->mFocused = state.value("focused").toBool();
- d->mCheckState = (Qt::CheckState)state.value("checkState").toInt();
+ if (state.count()) {
+ d->mCheckState = (Qt::CheckState)state.value("checkState").toInt();
+ } else
+ d->mCheckState = Qt::Unchecked;
}
/*!
@@ -561,13 +718,12 @@
}
}
- if (d->mPressed) {
- option->state |= QStyle::State_Sunken;
- }
if ( sd->mItemView
&& sd->mItemView->selectionMode() == HbAbstractItemView::SingleSelection){
option->singleSelectionMode = true;
- }
+ } else {
+ option->singleSelectionMode = false;
+ }
option->insidePopup = testAttribute(Hb::InsidePopup);
}
@@ -578,11 +734,11 @@
Default selection areas are for
\li HbAbstractViewItem::SingleSelection mode: whole item
\li HbAbstractViewItem::MultiSelection mode: whole item.
- \li HbAbstractViewItem::ContiguousSelection mode: area of HbStyle::P_ItemViewItem_touchmultiselection icon.
+ \li HbAbstractViewItem::ContiguousSelection mode: area of HbStylePrivate::P_ItemViewItem_touchmultiselection icon.
The \a selectionAreaType tells what kind of selection area is requested. The parameter value ContiguousSelection returns
the area where mouse movement will extend the selection to new items. By default this contiguous selection area is
- the HbStyle::P_ItemViewItem_touchmultiselection.
+ the HbStylePrivate::P_ItemViewItem_touchmultiselection.
*/
bool HbAbstractViewItem::selectionAreaContains(const QPointF &position, SelectionAreaType selectionAreaType) const
@@ -616,48 +772,78 @@
*/
bool HbAbstractViewItem::event(QEvent *e)
{
- if (e) {
- switch (e->type()) {
- case QEvent::GraphicsSceneResize: {
- Q_D(HbAbstractViewItem );
- if (d->mBackgroundItem || d->mFrame || d->mFocusItem) {
- HbStyleOptionAbstractViewItem styleOption;
- initStyleOption(&styleOption);
- if (d->mFocusItem) {
- style()->updatePrimitive(d->mFocusItem, HbStyle::P_ItemViewItem_focus, &styleOption);
- }
+ switch (e->type()) {
+ case QEvent::GraphicsSceneResize: {
+ Q_D(HbAbstractViewItem );
+ d->releasePixmaps();
+
+ updatePixmapCache();
+
+ QGraphicsSceneResizeEvent *resizeEvent = static_cast<QGraphicsSceneResizeEvent *>(e);
+
+ if (d->mFrontPixmapPainter) {
+ d->mFrontPixmapPainter->setSize(resizeEvent->newSize());
+ }
- if (d->mFrame) {
- style()->updatePrimitive(d->mFrame, HbStyle::P_ItemViewItem_frame, &styleOption);
- }
+ if (d->mBackPixmapPainter) {
+ d->mBackPixmapPainter->setSize(resizeEvent->newSize());
+ }
- if (d->mBackgroundItem) {
- style()->updatePrimitive(d->mBackgroundItem, HbStyle::P_ItemViewItem_background, &styleOption);
- }
+ if (d->mBackgroundItem || d->mFrame || d->mFocusItem) {
+ initStyleOption(d->mSharedData->mStyleOption);
+ if (d->mFocusItem) {
+ HbStylePrivate::updatePrimitive(d->mFocusItem, HbStylePrivate::P_ItemViewItem_focus, d->mSharedData->mStyleOption);
}
- break;
+
+ if (d->mFrame) {
+ HbStylePrivate::updatePrimitive(d->mFrame, HbStylePrivate::P_ItemViewItem_frame, d->mSharedData->mStyleOption);
+ }
+
+ if (d->mBackgroundItem) {
+ HbStylePrivate::updatePrimitive(d->mBackgroundItem, HbStylePrivate::P_ItemViewItem_background, d->mSharedData->mStyleOption);
+ }
}
- case QEvent::LayoutDirectionChange: {
- repolish();
- break;
+ break;
+ }
+ case QEvent::LayoutDirectionChange: {
+ repolish();
+ updatePixmapCache();
+ break;
+ }
+ case QEvent::LayoutRequest: {
+ updatePixmapCache();
+ break;
+ }
+ default: {
+ if (e->type() == HbAbstractViewItemShared::ViewItemDeferredDeleteEvent) {
+ // cannot handle ViewItemDeferredDeleteEvent in the case statement!
+ Q_D(HbAbstractViewItem);
+
+ d->mNonCachableItem = 0;
+
+ delete d->mFocusItem;
+ d->mFocusItem = 0;
+
+ updatePixmapCache();
}
- default: {
- if (e->type() == HbAbstractViewItemShared::ViewItemDeferredDeleteEvent) {
- // cannot handle ViewItemDeferredDeleteEvent in the case statement!
- Q_D(HbAbstractViewItem);
- delete d->mFocusItem;
- d->mFocusItem = 0;
- }
- break;
- }
+ break;
}
-
- return HbWidget::event(e);
}
+ return HbWidget::event(e);
+}
- return false;
+/*!
+ \reimp
+*/
+void HbAbstractViewItem::changeEvent(QEvent *event)
+{
+ if (event->type() == HbEvent::ThemeChanged) {
+ updatePixmapCache();
+ }
+ HbWidget::changeEvent(event);
}
+
/*!
\reimp
@@ -666,20 +852,41 @@
QVariant HbAbstractViewItem::itemChange(GraphicsItemChange change, const QVariant &value)
{
switch (change) {
- case ItemTransformHasChanged: {
+ case ItemTransformHasChanged: {
+ Q_D(HbAbstractViewItem);
+
QGraphicsLayoutItem *parentLayoutItem = this->parentLayoutItem();
if (parentLayoutItem && parentLayoutItem->isLayout()) {
QGraphicsLayout *parentLayout = static_cast<QGraphicsLayout *>(parentLayoutItem);
parentLayout->invalidate();
}
+ d->releasePixmaps();
+
+ updatePixmapCache();
break;
}
- case ItemEnabledHasChanged: {
+ case ItemEnabledHasChanged: {
updateChildItems();
break;
}
- default:
+ case ItemVisibleHasChanged: {
+ Q_D(HbAbstractViewItem);
+ if (!value.toBool() && d->usePixmapCache()) {
+ d->setChildFlags(0, false);
+ d->releasePixmaps();
+ d->mResetPixmapCache = true;
+ }
break;
+ }
+ case ItemChildAddedChange: {
+ Q_D(HbAbstractViewItem);
+ if (d->usePixmapCache()) {
+ d->setChildFlags(qvariant_cast<QGraphicsItem *>(value), true);
+ }
+ break;
+ }
+ default:
+ break;
}
return HbWidget::itemChange(change, value);
@@ -728,28 +935,29 @@
#endif
- HbStyleOptionAbstractViewItem styleOption;
- initStyleOption(&styleOption);
+ initStyleOption(d->mSharedData->mStyleOption);
if (d->mBackgroundItem) {
- style()->updatePrimitive(d->mBackgroundItem, HbStyle::P_ItemViewItem_background, &styleOption);
+ HbStylePrivate::updatePrimitive(d->mBackgroundItem, HbStylePrivate::P_ItemViewItem_background, d->mSharedData->mStyleOption);
}
if (d->mFrame) {
- style()->updatePrimitive(d->mFrame, HbStyle::P_ItemViewItem_frame, &styleOption);
+ HbStylePrivate::updatePrimitive(d->mFrame, HbStylePrivate::P_ItemViewItem_frame, d->mSharedData->mStyleOption);
}
if (d->mSelectionItem) {
- style()->updatePrimitive(d->mSelectionItem, HbStyle::P_ItemViewItem_selection, &styleOption);
+ HbStylePrivate::updatePrimitive(d->mSelectionItem, HbStylePrivate::P_ItemViewItem_selection, d->mSharedData->mStyleOption);
}
if (d->mMultiSelectionTouchArea) {
- style()->updatePrimitive(d->mMultiSelectionTouchArea, HbStyle::P_ItemViewItem_touchmultiselection, &styleOption);
+ HbStylePrivate::updatePrimitive(d->mMultiSelectionTouchArea, HbStylePrivate::P_ItemViewItem_touchmultiselection, d->mSharedData->mStyleOption);
}
if (d->mFocusItem) {
- style()->updatePrimitive(d->mFocusItem, HbStyle::P_ItemViewItem_focus, &styleOption);
+ HbStylePrivate::updatePrimitive(d->mFocusItem, HbStylePrivate::P_ItemViewItem_focus, d->mSharedData->mStyleOption);
}
+
+ updatePixmapCache();
}
@@ -801,14 +1009,14 @@
|| currentBackground.canConvert<QBrush>()) {
if (!d->mBackgroundItem) {
d->mItemsChanged = true;
- d->mBackgroundItem = style()->createPrimitive(HbStyle::P_ItemViewItem_background, this);
+ d->mBackgroundItem = HbStylePrivate::createPrimitive(HbStylePrivate::P_ItemViewItem_background, this);
delete d->mFrame;
d->mFrame = 0;
}
} else if (currentBackground.canConvert<HbFrameBackground>()) {
if (!d->mFrame) {
d->mItemsChanged = true;
- d->mFrame = style()->createPrimitive(HbStyle::P_ItemViewItem_frame, this);
+ d->mFrame = HbStylePrivate::createPrimitive(HbStylePrivate::P_ItemViewItem_frame, this);
delete d->mBackgroundItem;
d->mBackgroundItem = 0;
}
@@ -829,7 +1037,7 @@
|| sd->mDefaultFrame.isNull()))) {
if (!d->mFrame) {
d->mItemsChanged = true;
- d->mFrame = style()->createPrimitive(HbStyle::P_ItemViewItem_frame, this);
+ d->mFrame = HbStylePrivate::createPrimitive(HbStylePrivate::P_ItemViewItem_frame, this);
}
} else if (d->mFrame) {
d->mItemsChanged = true;
@@ -879,7 +1087,7 @@
if (itemSelectable) {
if (!d->mSelectionItem) {
d->mItemsChanged = true;
- d->mSelectionItem = style()->createPrimitive(HbStyle::P_ItemViewItem_selection, this);
+ d->mSelectionItem = HbStylePrivate::createPrimitive(HbStylePrivate::P_ItemViewItem_selection, this);
}
} else {
d->mItemsChanged = true;
@@ -895,7 +1103,7 @@
&& selectionMode == HbAbstractItemView::MultiSelection) {
if (!d->mMultiSelectionTouchArea) {
d->mItemsChanged = true;
- d->mMultiSelectionTouchArea = style()->createPrimitive(HbStyle::P_ItemViewItem_touchmultiselection, this);
+ d->mMultiSelectionTouchArea = HbStylePrivate::createPrimitive(HbStylePrivate::P_ItemViewItem_touchmultiselection, this);
}
} else if (d->mMultiSelectionTouchArea) {
d->mItemsChanged = true;
@@ -965,22 +1173,26 @@
if (sd->mItemView && !(sd->mItemView->enabledAnimations() & HbAbstractItemView::TouchDown)) {
doAnimate = false;
}
+
if (pressed) {
if (!d->mFocusItem) {
- d->mFocusItem = style()->createPrimitive(HbStyle::P_ItemViewItem_focus, this);
+ d->mFocusItem = HbStylePrivate::createPrimitive(HbStylePrivate::P_ItemViewItem_focus, this);
+ d->setChildFlags(d->mFocusItem, false);
}
- HbStyleOptionAbstractViewItem styleOption;
- initStyleOption(&styleOption);
+ initStyleOption(d->mSharedData->mStyleOption);
if (d->mFocusItem) {
- style()->updatePrimitive(d->mFocusItem, HbStyle::P_ItemViewItem_focus, &styleOption);
+ HbStylePrivate::updatePrimitive(d->mFocusItem, HbStylePrivate::P_ItemViewItem_focus, d->mSharedData->mStyleOption);
}
if (doAnimate) {
HbEffect::cancel(this, "released");
HbEffect::cancel(d->mFocusItem, "released");
+ d->mNonCachableItem = d->mFocusItem;
+ updatePixmapCache();
+
HbEffect::start(this, sd->mItemType, "pressed");
HbEffect::start(d->mFocusItem, sd->mItemType + QString("-focus"), "pressed");
}
@@ -989,6 +1201,9 @@
HbEffect::cancel(this, "pressed");
HbEffect::cancel(d->mFocusItem, "pressed");
+ d->mNonCachableItem = d->mFocusItem;
+ updatePixmapCache();
+
HbEffect::start(this, sd->mItemType, "released");
HbEffect::start(d->mFocusItem, sd->mItemType + QString("-focus"), "released", this, "_q_animationFinished");
} else {
@@ -1001,6 +1216,10 @@
}
}
}
+
+ if (d->mNonCachableItem && !d->mBackPixmapPainter) {
+ d->mBackPixmapPainter = new HbViewItemPixmapPainter(-1000, this);
+ }
}
/*!
@@ -1020,9 +1239,13 @@
HB_SDD(HbAbstractViewItem);
if (!d->polished && layout()) {
- return;
+ return;
}
+ if (d->polished && !d->repolishOutstanding && !d->mRepolishRequested) {
+ return;
+ }
+
if (sd->mItemView) {
setProperty("layoutName", sd->mItemView->layoutName());
}
@@ -1117,6 +1340,83 @@
}
}
+/*!
+ \reimp
+*/
+void HbAbstractViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ Q_UNUSED(widget);
+
+ Q_D(HbAbstractViewItem);
+
+ if (!d->mInPaintItems) {
+ bool usePixmapCache = d->usePixmapCache();
+
+ if (usePixmapCache) {
+ QRectF deviceBounds = painter->worldTransform().mapRect(boundingRect());
+ QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1);
+
+ if (d->mResetPixmapCache) {
+ if (!d->mFrontCachePixmap) {
+ d->setChildFlags(0, true);
+
+ d->mFrontCachePixmap = new QPixmap(deviceRect.size());
+ d->mFrontPixmapPainter->setPixmap(d->mFrontCachePixmap);
+ }
+
+ // Construct an item-to-pixmap transform.
+ QPointF p = deviceRect.topLeft();
+ QTransform itemToPixmap = painter->worldTransform();
+ if (!p.isNull())
+ itemToPixmap *= QTransform::fromTranslate(-p.x(), -p.y());
+
+ d->updatePixmap(d->mFrontCachePixmap, painter, itemToPixmap, option, d->mNonCachableItem, 0);
+
+ if (d->mNonCachableItem) {
+ if (!d->mBackCachePixmap) {
+ d->mBackCachePixmap = new QPixmap(deviceRect.size());
+ }
+ d->mBackPixmapPainter->setPixmap(d->mBackCachePixmap);
+ d->updatePixmap(d->mBackCachePixmap, painter, itemToPixmap, option, 0, d->mNonCachableItem);
+ } else if (d->mBackPixmapPainter) {
+ d->mBackPixmapPainter->setPixmap(0);
+ }
+
+ d->mResetPixmapCache = false;
+ }
+
+ if (d->mBackPixmapPainter) {
+ d->mBackPixmapPainter->setDeviceRect(deviceRect);
+ }
+
+ if (d->mFrontPixmapPainter) {
+ d->mFrontPixmapPainter->setDeviceRect(deviceRect);
+ }
+ } else {
+ if (d->mFrontCachePixmap) {
+ d->setChildFlags(0, false);
+
+ d->releasePixmaps();
+ }
+ }
+ }
+}
+
+/*!
+ Updates the pixmap cache.
+
+ Call this function when cache pixmap requires updating due to item or child state change
+ that affects its visual appearance.
+*/
+void HbAbstractViewItem::updatePixmapCache()
+{
+ Q_D(HbAbstractViewItem);
+
+ if (d->usePixmapCache()) {
+ d->mResetPixmapCache = true;
+ update();
+ }
+}
#include "moc_hbabstractviewitem.cpp"