Merge branch 'master' of git://scm.dev.nokia.troll.no/qt/qtbase-staging
This commit is contained in:
commit
dd1a7a6379
@ -1,8 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2011 Klarälvdalens Datakonsult AB,
|
** Copyright (C) 2011 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly <stephen.kelly@kdab.com>
|
||||||
** a KDAB Group company, info@kdab.com,
|
|
||||||
** author Stephen Kelly <stephen.kelly@kdab.com>
|
|
||||||
** All rights reserved.
|
** All rights reserved.
|
||||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||||
**
|
**
|
||||||
|
@ -2647,10 +2647,7 @@ MakefileGenerator::writeSubTargets(QTextStream &t, QList<MakefileGenerator::SubT
|
|||||||
QString out_directory_cdin, out_directory_cdout;
|
QString out_directory_cdin, out_directory_cdout;
|
||||||
MAKE_CD_IN_AND_OUT(out_directory);
|
MAKE_CD_IN_AND_OUT(out_directory);
|
||||||
|
|
||||||
//don't need the makefile arg if it isn't changed
|
QString makefilein = " -f " + subtarget->makefile;
|
||||||
QString makefilein;
|
|
||||||
if(subtarget->makefile != "$(MAKEFILE)")
|
|
||||||
makefilein = " -f " + subtarget->makefile;
|
|
||||||
|
|
||||||
//write the rule/depends
|
//write the rule/depends
|
||||||
if(flags & SubTargetOrdered) {
|
if(flags & SubTargetOrdered) {
|
||||||
|
@ -111,8 +111,8 @@ public:
|
|||||||
TableSummaryChanged,
|
TableSummaryChanged,
|
||||||
TextAttributeChanged,
|
TextAttributeChanged,
|
||||||
TextCaretMoved,
|
TextCaretMoved,
|
||||||
TextChanged,
|
// TextChanged, deprecated, use TextUpdated
|
||||||
TextColumnChanged,
|
TextColumnChanged = TextCaretMoved + 2,
|
||||||
TextInserted,
|
TextInserted,
|
||||||
TextRemoved,
|
TextRemoved,
|
||||||
TextUpdated,
|
TextUpdated,
|
||||||
|
@ -269,12 +269,20 @@ void QGraphicsLayout::activate()
|
|||||||
return;
|
return;
|
||||||
Q_ASSERT(!parentItem->isLayout());
|
Q_ASSERT(!parentItem->isLayout());
|
||||||
|
|
||||||
setGeometry(parentItem->contentsRect()); // relayout children
|
if (QGraphicsLayout::instantInvalidatePropagation()) {
|
||||||
|
QGraphicsWidget *parentWidget = static_cast<QGraphicsWidget*>(parentItem);
|
||||||
|
if (!parentWidget->parentLayoutItem()) {
|
||||||
|
// we've reached the topmost widget, resize it
|
||||||
|
bool wasResized = parentWidget->testAttribute(Qt::WA_Resized);
|
||||||
|
parentWidget->resize(parentWidget->size());
|
||||||
|
parentWidget->setAttribute(Qt::WA_Resized, wasResized);
|
||||||
|
}
|
||||||
|
|
||||||
// ### bug, should be parentItem ?
|
setGeometry(parentItem->contentsRect()); // relayout children
|
||||||
parentLayoutItem()->updateGeometry(); // bubble up; will set activated to false
|
} else {
|
||||||
// ### too many resizes? maybe we should walk up the chain to the
|
setGeometry(parentItem->contentsRect()); // relayout children
|
||||||
// ### top-level layouted layoutItem and call activate there.
|
parentLayoutItem()->updateGeometry();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -300,32 +308,36 @@ bool QGraphicsLayout::isActivated() const
|
|||||||
*/
|
*/
|
||||||
void QGraphicsLayout::invalidate()
|
void QGraphicsLayout::invalidate()
|
||||||
{
|
{
|
||||||
// only mark layouts as invalid (activated = false) if we can post a LayoutRequest event.
|
if (QGraphicsLayout::instantInvalidatePropagation()) {
|
||||||
QGraphicsLayoutItem *layoutItem = this;
|
updateGeometry();
|
||||||
while (layoutItem && layoutItem->isLayout()) {
|
} else {
|
||||||
// we could call updateGeometry(), but what if that method
|
// only mark layouts as invalid (activated = false) if we can post a LayoutRequest event.
|
||||||
// does not call the base implementation? In addition, updateGeometry()
|
QGraphicsLayoutItem *layoutItem = this;
|
||||||
// does more than we need.
|
while (layoutItem && layoutItem->isLayout()) {
|
||||||
layoutItem->d_func()->sizeHintCacheDirty = true;
|
// we could call updateGeometry(), but what if that method
|
||||||
layoutItem->d_func()->sizeHintWithConstraintCacheDirty = true;
|
// does not call the base implementation? In addition, updateGeometry()
|
||||||
layoutItem = layoutItem->parentLayoutItem();
|
// does more than we need.
|
||||||
}
|
layoutItem->d_func()->sizeHintCacheDirty = true;
|
||||||
if (layoutItem) {
|
layoutItem->d_func()->sizeHintWithConstraintCacheDirty = true;
|
||||||
layoutItem->d_func()->sizeHintCacheDirty = true;
|
|
||||||
layoutItem->d_func()->sizeHintWithConstraintCacheDirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool postIt = layoutItem ? !layoutItem->isLayout() : false;
|
|
||||||
if (postIt) {
|
|
||||||
layoutItem = this;
|
|
||||||
while (layoutItem && layoutItem->isLayout()
|
|
||||||
&& static_cast<QGraphicsLayout*>(layoutItem)->d_func()->activated) {
|
|
||||||
static_cast<QGraphicsLayout*>(layoutItem)->d_func()->activated = false;
|
|
||||||
layoutItem = layoutItem->parentLayoutItem();
|
layoutItem = layoutItem->parentLayoutItem();
|
||||||
}
|
}
|
||||||
if (layoutItem && !layoutItem->isLayout()) {
|
if (layoutItem) {
|
||||||
// If a layout has a parent that is not a layout it must be a QGraphicsWidget.
|
layoutItem->d_func()->sizeHintCacheDirty = true;
|
||||||
QApplication::postEvent(static_cast<QGraphicsWidget *>(layoutItem), new QEvent(QEvent::LayoutRequest));
|
layoutItem->d_func()->sizeHintWithConstraintCacheDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool postIt = layoutItem ? !layoutItem->isLayout() : false;
|
||||||
|
if (postIt) {
|
||||||
|
layoutItem = this;
|
||||||
|
while (layoutItem && layoutItem->isLayout()
|
||||||
|
&& static_cast<QGraphicsLayout*>(layoutItem)->d_func()->activated) {
|
||||||
|
static_cast<QGraphicsLayout*>(layoutItem)->d_func()->activated = false;
|
||||||
|
layoutItem = layoutItem->parentLayoutItem();
|
||||||
|
}
|
||||||
|
if (layoutItem && !layoutItem->isLayout()) {
|
||||||
|
// If a layout has a parent that is not a layout it must be a QGraphicsWidget.
|
||||||
|
QApplication::postEvent(static_cast<QGraphicsWidget *>(layoutItem), new QEvent(QEvent::LayoutRequest));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -335,12 +347,27 @@ void QGraphicsLayout::invalidate()
|
|||||||
*/
|
*/
|
||||||
void QGraphicsLayout::updateGeometry()
|
void QGraphicsLayout::updateGeometry()
|
||||||
{
|
{
|
||||||
QGraphicsLayoutItem::updateGeometry();
|
Q_D(QGraphicsLayout);
|
||||||
if (QGraphicsLayoutItem *parentItem = parentLayoutItem()) {
|
if (QGraphicsLayout::instantInvalidatePropagation()) {
|
||||||
if (parentItem->isLayout()) {
|
d->activated = false;
|
||||||
|
QGraphicsLayoutItem::updateGeometry();
|
||||||
|
|
||||||
|
QGraphicsLayoutItem *parentItem = parentLayoutItem();
|
||||||
|
if (!parentItem)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (parentItem->isLayout())
|
||||||
|
static_cast<QGraphicsLayout *>(parentItem)->invalidate();
|
||||||
|
else
|
||||||
parentItem->updateGeometry();
|
parentItem->updateGeometry();
|
||||||
} else {
|
} else {
|
||||||
invalidate();
|
QGraphicsLayoutItem::updateGeometry();
|
||||||
|
if (QGraphicsLayoutItem *parentItem = parentLayoutItem()) {
|
||||||
|
if (parentItem->isLayout()) {
|
||||||
|
parentItem->updateGeometry();
|
||||||
|
} else {
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -446,6 +473,50 @@ void QGraphicsLayout::addChildLayoutItem(QGraphicsLayoutItem *layoutItem)
|
|||||||
d->addChildLayoutItem(layoutItem);
|
d->addChildLayoutItem(layoutItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool g_instantInvalidatePropagation = false;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\internal
|
||||||
|
\since 4.8
|
||||||
|
\see instantInvalidatePropagation
|
||||||
|
|
||||||
|
Calling this function with \a enable set to true will enable a feature that
|
||||||
|
makes propagation of invalidation up to ancestor layout items to be done in
|
||||||
|
one go. It will propagate up the parentLayoutItem() hierarchy until it has
|
||||||
|
reached the root. If the root item is a QGraphicsWidget, it will *post* a
|
||||||
|
layout request to it. When the layout request is consumed it will traverse
|
||||||
|
down the hierarchy of layouts and widgets and activate all layouts that is
|
||||||
|
invalid (not activated). This is the recommended behaviour.
|
||||||
|
|
||||||
|
If not set it will also propagate up the parentLayoutItem() hierarchy, but
|
||||||
|
it will stop at the \i first \i widget it encounters, and post a layout
|
||||||
|
request to the widget. When the layout request is consumed, this might
|
||||||
|
cause it to continue propagation up to the parentLayoutItem() of the
|
||||||
|
widget. It will continue in this fashion until it has reached a widget with
|
||||||
|
no parentLayoutItem(). This strategy might cause drawing artifacts, since
|
||||||
|
it is not done in one go, and the consumption of layout requests might be
|
||||||
|
interleaved by consumption of paint events, which might cause significant
|
||||||
|
flicker.
|
||||||
|
Note, this is not the recommended behavior, but for compatibility reasons
|
||||||
|
this is the default behaviour.
|
||||||
|
*/
|
||||||
|
void QGraphicsLayout::setInstantInvalidatePropagation(bool enable)
|
||||||
|
{
|
||||||
|
g_instantInvalidatePropagation = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\internal
|
||||||
|
\since 4.8
|
||||||
|
\see setInstantInvalidatePropagation
|
||||||
|
|
||||||
|
returns true if the complete widget/layout hierarchy is rearranged in one go.
|
||||||
|
*/
|
||||||
|
bool QGraphicsLayout::instantInvalidatePropagation()
|
||||||
|
{
|
||||||
|
return g_instantInvalidatePropagation;
|
||||||
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
#endif //QT_NO_GRAPHICSVIEW
|
#endif //QT_NO_GRAPHICSVIEW
|
||||||
|
@ -76,6 +76,8 @@ public:
|
|||||||
virtual QGraphicsLayoutItem *itemAt(int i) const = 0;
|
virtual QGraphicsLayoutItem *itemAt(int i) const = 0;
|
||||||
virtual void removeAt(int index) = 0;
|
virtual void removeAt(int index) = 0;
|
||||||
|
|
||||||
|
static void setInstantInvalidatePropagation(bool enable);
|
||||||
|
static bool instantInvalidatePropagation();
|
||||||
protected:
|
protected:
|
||||||
QGraphicsLayout(QGraphicsLayoutPrivate &, QGraphicsLayoutItem *);
|
QGraphicsLayout(QGraphicsLayoutPrivate &, QGraphicsLayoutItem *);
|
||||||
void addChildLayoutItem(QGraphicsLayoutItem *layoutItem);
|
void addChildLayoutItem(QGraphicsLayoutItem *layoutItem);
|
||||||
|
@ -180,9 +180,14 @@ void QGraphicsLayoutPrivate::activateRecursive(QGraphicsLayoutItem *item)
|
|||||||
{
|
{
|
||||||
if (item->isLayout()) {
|
if (item->isLayout()) {
|
||||||
QGraphicsLayout *layout = static_cast<QGraphicsLayout *>(item);
|
QGraphicsLayout *layout = static_cast<QGraphicsLayout *>(item);
|
||||||
if (layout->d_func()->activated)
|
if (layout->d_func()->activated) {
|
||||||
layout->invalidate();
|
if (QGraphicsLayout::instantInvalidatePropagation()) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
layout->invalidate(); // ### LOOKS SUSPICIOUSLY WRONG!!???
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = layout->count() - 1; i >= 0; --i) {
|
for (int i = layout->count() - 1; i >= 0; --i) {
|
||||||
QGraphicsLayoutItem *childItem = layout->itemAt(i);
|
QGraphicsLayoutItem *childItem = layout->itemAt(i);
|
||||||
if (childItem)
|
if (childItem)
|
||||||
|
@ -275,17 +275,13 @@ void QGraphicsLinearLayout::insertItem(int index, QGraphicsLayoutItem *item)
|
|||||||
qWarning("QGraphicsLinearLayout::insertItem: cannot insert itself");
|
qWarning("QGraphicsLinearLayout::insertItem: cannot insert itself");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Q_ASSERT(item);
|
|
||||||
|
|
||||||
//the order of the following instructions is very important because
|
|
||||||
//invalidating the layout before adding the child item will make the layout happen
|
|
||||||
//before we try to paint the item
|
|
||||||
invalidate();
|
|
||||||
d->addChildLayoutItem(item);
|
d->addChildLayoutItem(item);
|
||||||
|
|
||||||
|
Q_ASSERT(item);
|
||||||
d->fixIndex(&index);
|
d->fixIndex(&index);
|
||||||
d->engine.insertRow(index, d->orientation);
|
d->engine.insertRow(index, d->orientation);
|
||||||
new QGridLayoutItem(&d->engine, item, d->gridRow(index), d->gridColumn(index), 1, 1, 0, index);
|
new QGridLayoutItem(&d->engine, item, d->gridRow(index), d->gridColumn(index), 1, 1, 0, index);
|
||||||
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -354,8 +354,10 @@ void QGraphicsWidget::setGeometry(const QRectF &rect)
|
|||||||
newGeom = rect;
|
newGeom = rect;
|
||||||
newGeom.setSize(rect.size().expandedTo(effectiveSizeHint(Qt::MinimumSize))
|
newGeom.setSize(rect.size().expandedTo(effectiveSizeHint(Qt::MinimumSize))
|
||||||
.boundedTo(effectiveSizeHint(Qt::MaximumSize)));
|
.boundedTo(effectiveSizeHint(Qt::MaximumSize)));
|
||||||
if (newGeom == d->geom)
|
|
||||||
return;
|
if (newGeom == d->geom) {
|
||||||
|
goto relayoutChildrenAndReturn;
|
||||||
|
}
|
||||||
|
|
||||||
// setPos triggers ItemPositionChange, which can adjust position
|
// setPos triggers ItemPositionChange, which can adjust position
|
||||||
wd->inSetGeometry = 1;
|
wd->inSetGeometry = 1;
|
||||||
@ -363,8 +365,9 @@ void QGraphicsWidget::setGeometry(const QRectF &rect)
|
|||||||
wd->inSetGeometry = 0;
|
wd->inSetGeometry = 0;
|
||||||
newGeom.moveTopLeft(pos());
|
newGeom.moveTopLeft(pos());
|
||||||
|
|
||||||
if (newGeom == d->geom)
|
if (newGeom == d->geom) {
|
||||||
return;
|
goto relayoutChildrenAndReturn;
|
||||||
|
}
|
||||||
|
|
||||||
// Update and prepare to change the geometry (remove from index) if the size has changed.
|
// Update and prepare to change the geometry (remove from index) if the size has changed.
|
||||||
if (wd->scene) {
|
if (wd->scene) {
|
||||||
@ -375,35 +378,54 @@ void QGraphicsWidget::setGeometry(const QRectF &rect)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update the layout item geometry
|
// Update the layout item geometry
|
||||||
bool moved = oldPos != pos();
|
{
|
||||||
if (moved) {
|
bool moved = oldPos != pos();
|
||||||
// Send move event.
|
if (moved) {
|
||||||
QGraphicsSceneMoveEvent event;
|
// Send move event.
|
||||||
event.setOldPos(oldPos);
|
QGraphicsSceneMoveEvent event;
|
||||||
event.setNewPos(pos());
|
event.setOldPos(oldPos);
|
||||||
QApplication::sendEvent(this, &event);
|
event.setNewPos(pos());
|
||||||
if (wd->inSetPos) {
|
QApplication::sendEvent(this, &event);
|
||||||
//set the new pos
|
if (wd->inSetPos) {
|
||||||
d->geom.moveTopLeft(pos());
|
//set the new pos
|
||||||
emit geometryChanged();
|
d->geom.moveTopLeft(pos());
|
||||||
return;
|
emit geometryChanged();
|
||||||
|
goto relayoutChildrenAndReturn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QSizeF oldSize = size();
|
||||||
|
QGraphicsLayoutItem::setGeometry(newGeom);
|
||||||
|
// Send resize event
|
||||||
|
bool resized = newGeom.size() != oldSize;
|
||||||
|
if (resized) {
|
||||||
|
QGraphicsSceneResizeEvent re;
|
||||||
|
re.setOldSize(oldSize);
|
||||||
|
re.setNewSize(newGeom.size());
|
||||||
|
if (oldSize.width() != newGeom.size().width())
|
||||||
|
emit widthChanged();
|
||||||
|
if (oldSize.height() != newGeom.size().height())
|
||||||
|
emit heightChanged();
|
||||||
|
QGraphicsLayout *lay = wd->layout;
|
||||||
|
if (QGraphicsLayout::instantInvalidatePropagation()) {
|
||||||
|
if (!lay || lay->isActivated()) {
|
||||||
|
QApplication::sendEvent(this, &re);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QApplication::sendEvent(this, &re);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QSizeF oldSize = size();
|
|
||||||
QGraphicsLayoutItem::setGeometry(newGeom);
|
|
||||||
// Send resize event
|
|
||||||
bool resized = newGeom.size() != oldSize;
|
|
||||||
if (resized) {
|
|
||||||
QGraphicsSceneResizeEvent re;
|
|
||||||
re.setOldSize(oldSize);
|
|
||||||
re.setNewSize(newGeom.size());
|
|
||||||
if (oldSize.width() != newGeom.size().width())
|
|
||||||
emit widthChanged();
|
|
||||||
if (oldSize.height() != newGeom.size().height())
|
|
||||||
emit heightChanged();
|
|
||||||
QApplication::sendEvent(this, &re);
|
|
||||||
}
|
|
||||||
emit geometryChanged();
|
emit geometryChanged();
|
||||||
|
relayoutChildrenAndReturn:
|
||||||
|
if (QGraphicsLayout::instantInvalidatePropagation()) {
|
||||||
|
if (QGraphicsLayout *lay = wd->layout) {
|
||||||
|
if (!lay->isActivated()) {
|
||||||
|
QEvent layoutRequest(QEvent::LayoutRequest);
|
||||||
|
QApplication::sendEvent(this, &layoutRequest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -1052,16 +1074,31 @@ void QGraphicsWidget::updateGeometry()
|
|||||||
QGraphicsLayoutItem *parentItem = parentLayoutItem();
|
QGraphicsLayoutItem *parentItem = parentLayoutItem();
|
||||||
|
|
||||||
if (parentItem && parentItem->isLayout()) {
|
if (parentItem && parentItem->isLayout()) {
|
||||||
parentItem->updateGeometry();
|
if (QGraphicsLayout::instantInvalidatePropagation()) {
|
||||||
|
static_cast<QGraphicsLayout *>(parentItem)->invalidate();
|
||||||
|
} else {
|
||||||
|
parentItem->updateGeometry();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (parentItem) {
|
if (parentItem) {
|
||||||
|
// This is for custom layouting
|
||||||
QGraphicsWidget *parentWid = parentWidget(); //###
|
QGraphicsWidget *parentWid = parentWidget(); //###
|
||||||
if (parentWid->isVisible())
|
if (parentWid->isVisible())
|
||||||
QApplication::postEvent(parentWid, new QEvent(QEvent::LayoutRequest));
|
QApplication::postEvent(parentWid, new QEvent(QEvent::LayoutRequest));
|
||||||
|
} else {
|
||||||
|
/**
|
||||||
|
* If this is the topmost widget, post a LayoutRequest event to the widget.
|
||||||
|
* When the event is received, it will start flowing all the way down to the leaf
|
||||||
|
* widgets in one go. This will make a relayout flicker-free.
|
||||||
|
*/
|
||||||
|
if (QGraphicsLayout::instantInvalidatePropagation())
|
||||||
|
QApplication::postEvent(static_cast<QGraphicsWidget *>(this), new QEvent(QEvent::LayoutRequest));
|
||||||
|
}
|
||||||
|
if (!QGraphicsLayout::instantInvalidatePropagation()) {
|
||||||
|
bool wasResized = testAttribute(Qt::WA_Resized);
|
||||||
|
resize(size()); // this will restrict the size
|
||||||
|
setAttribute(Qt::WA_Resized, wasResized);
|
||||||
}
|
}
|
||||||
bool wasResized = testAttribute(Qt::WA_Resized);
|
|
||||||
resize(size()); // this will restrict the size
|
|
||||||
setAttribute(Qt::WA_Resized, wasResized);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,18 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2011 Klarälvdalens Datakonsult AB,
|
** Copyright (C) 2011 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly <stephen.kelly@kdab.com>
|
||||||
** a KDAB Group company, info@kdab.com,
|
|
||||||
** author Stephen Kelly <stephen.kelly@kdab.com>
|
|
||||||
** All rights reserved.
|
** All rights reserved.
|
||||||
** Contact: Nokia Corporation (info@qt.nokia.com)
|
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||||
**
|
**
|
||||||
** This file is part of the QtGui module of the Qt Toolkit.
|
** This file is part of the QtGui module of the Qt Toolkit.
|
||||||
**
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:LGPL$
|
||||||
|
** No Commercial Usage
|
||||||
|
** This file contains pre-release code and may not be distributed.
|
||||||
|
** You may use this file in accordance with the terms and conditions
|
||||||
|
** contained in the Technology Preview License Agreement accompanying
|
||||||
|
** this package.
|
||||||
|
**
|
||||||
** GNU Lesser General Public License Usage
|
** GNU Lesser General Public License Usage
|
||||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||||
** General Public License version 2.1 as published by the Free Software
|
** General Public License version 2.1 as published by the Free Software
|
||||||
@ -20,17 +25,17 @@
|
|||||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||||
**
|
**
|
||||||
** GNU General Public License Usage
|
** If you have questions regarding the use of this file, please contact
|
||||||
** Alternatively, this file may be used under the terms of the GNU General
|
** Nokia at qt-info@nokia.com.
|
||||||
** Public License version 3.0 as published by the Free Software Foundation
|
|
||||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
|
||||||
** file. Please review the following information to ensure the GNU General
|
|
||||||
** Public License version 3.0 requirements will be met:
|
|
||||||
** http://www.gnu.org/copyleft/gpl.html.
|
|
||||||
**
|
**
|
||||||
** Other Usage
|
**
|
||||||
** Alternatively, this file may be used in accordance with the terms and
|
**
|
||||||
** conditions contained in a signed written agreement between you and Nokia.
|
**
|
||||||
|
**
|
||||||
|
**
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
@ -1,13 +1,18 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2011 Klarälvdalens Datakonsult AB,
|
** Copyright (C) 2011 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly <stephen.kelly@kdab.com>
|
||||||
** a KDAB Group company, info@kdab.com,
|
|
||||||
** author Stephen Kelly <stephen.kelly@kdab.com>
|
|
||||||
** All rights reserved.
|
** All rights reserved.
|
||||||
** Contact: Nokia Corporation (info@qt.nokia.com)
|
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||||
**
|
**
|
||||||
** This file is part of the QtGui module of the Qt Toolkit.
|
** This file is part of the QtGui module of the Qt Toolkit.
|
||||||
**
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:LGPL$
|
||||||
|
** No Commercial Usage
|
||||||
|
** This file contains pre-release code and may not be distributed.
|
||||||
|
** You may use this file in accordance with the terms and conditions
|
||||||
|
** contained in the Technology Preview License Agreement accompanying
|
||||||
|
** this package.
|
||||||
|
**
|
||||||
** GNU Lesser General Public License Usage
|
** GNU Lesser General Public License Usage
|
||||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||||
** General Public License version 2.1 as published by the Free Software
|
** General Public License version 2.1 as published by the Free Software
|
||||||
@ -20,17 +25,17 @@
|
|||||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||||
**
|
**
|
||||||
** GNU General Public License Usage
|
** If you have questions regarding the use of this file, please contact
|
||||||
** Alternatively, this file may be used under the terms of the GNU General
|
** Nokia at qt-info@nokia.com.
|
||||||
** Public License version 3.0 as published by the Free Software Foundation
|
|
||||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
|
||||||
** file. Please review the following information to ensure the GNU General
|
|
||||||
** Public License version 3.0 requirements will be met:
|
|
||||||
** http://www.gnu.org/copyleft/gpl.html.
|
|
||||||
**
|
**
|
||||||
** Other Usage
|
**
|
||||||
** Alternatively, this file may be used in accordance with the terms and
|
**
|
||||||
** conditions contained in a signed written agreement between you and Nokia.
|
**
|
||||||
|
**
|
||||||
|
**
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ HEADERS += \
|
|||||||
painting/qcolor.h \
|
painting/qcolor.h \
|
||||||
painting/qcolor_p.h \
|
painting/qcolor_p.h \
|
||||||
painting/qcolormap.h \
|
painting/qcolormap.h \
|
||||||
|
painting/qcosmeticstroker_p.h \
|
||||||
painting/qdrawutil.h \
|
painting/qdrawutil.h \
|
||||||
painting/qemulationpaintengine_p.h \
|
painting/qemulationpaintengine_p.h \
|
||||||
painting/qgraphicssystem_p.h \
|
painting/qgraphicssystem_p.h \
|
||||||
@ -14,7 +15,7 @@ HEADERS += \
|
|||||||
painting/qoutlinemapper_p.h \
|
painting/qoutlinemapper_p.h \
|
||||||
painting/qpaintdevice.h \
|
painting/qpaintdevice.h \
|
||||||
painting/qpaintengine.h \
|
painting/qpaintengine.h \
|
||||||
painting/qpaintengine_p.h \
|
painting/qpaintengine_p.h \
|
||||||
painting/qpaintengine_alpha_p.h \
|
painting/qpaintengine_alpha_p.h \
|
||||||
painting/qpaintengine_preview_p.h \
|
painting/qpaintengine_preview_p.h \
|
||||||
painting/qpaintengineex_p.h \
|
painting/qpaintengineex_p.h \
|
||||||
@ -53,6 +54,7 @@ SOURCES += \
|
|||||||
painting/qbrush.cpp \
|
painting/qbrush.cpp \
|
||||||
painting/qcolor.cpp \
|
painting/qcolor.cpp \
|
||||||
painting/qcolor_p.cpp \
|
painting/qcolor_p.cpp \
|
||||||
|
painting/qcosmeticstroker.cpp \
|
||||||
painting/qcssutil.cpp \
|
painting/qcssutil.cpp \
|
||||||
painting/qdrawutil.cpp \
|
painting/qdrawutil.cpp \
|
||||||
painting/qemulationpaintengine.cpp \
|
painting/qemulationpaintengine.cpp \
|
||||||
|
958
src/gui/painting/qcosmeticstroker.cpp
Normal file
958
src/gui/painting/qcosmeticstroker.cpp
Normal file
@ -0,0 +1,958 @@
|
|||||||
|
#include "qcosmeticstroker_p.h"
|
||||||
|
#include "private/qpainterpath_p.h"
|
||||||
|
#include <qdebug.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
inline QString capString(int caps)
|
||||||
|
{
|
||||||
|
QString str;
|
||||||
|
if (caps & QCosmeticStroker::CapBegin) {
|
||||||
|
str += "CapBegin ";
|
||||||
|
}
|
||||||
|
if (caps & QCosmeticStroker::CapEnd) {
|
||||||
|
str += "CapEnd ";
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define toF26Dot6(x) ((int)((x)*64.))
|
||||||
|
|
||||||
|
static inline uint sourceOver(uint d, uint color)
|
||||||
|
{
|
||||||
|
return color + BYTE_MUL(d, qAlpha(~color));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static int F16Dot16FixedDiv(int x, int y)
|
||||||
|
{
|
||||||
|
if (qAbs(x) > 0x7fff)
|
||||||
|
return (((qlonglong)x) << 16) / y;
|
||||||
|
return (x << 16) / y;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef void (*DrawPixel)(QCosmeticStroker *stroker, int x, int y, int coverage);
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct Dasher {
|
||||||
|
QCosmeticStroker *stroker;
|
||||||
|
int *pattern;
|
||||||
|
int offset;
|
||||||
|
int dashIndex;
|
||||||
|
int dashOn;
|
||||||
|
|
||||||
|
Dasher(QCosmeticStroker *s, bool reverse, int start, int stop)
|
||||||
|
: stroker(s)
|
||||||
|
{
|
||||||
|
int delta = stop - start;
|
||||||
|
if (reverse) {
|
||||||
|
pattern = stroker->reversePattern;
|
||||||
|
offset = stroker->patternLength - stroker->patternOffset - delta - ((start & 63) - 32);
|
||||||
|
dashOn = 0;
|
||||||
|
} else {
|
||||||
|
pattern = stroker->pattern;
|
||||||
|
offset = stroker->patternOffset - ((start & 63) - 32);
|
||||||
|
dashOn = 1;
|
||||||
|
}
|
||||||
|
offset %= stroker->patternLength;
|
||||||
|
if (offset < 0)
|
||||||
|
offset += stroker->patternLength;
|
||||||
|
|
||||||
|
dashIndex = 0;
|
||||||
|
while (offset>= pattern[dashIndex])
|
||||||
|
++dashIndex;
|
||||||
|
|
||||||
|
// qDebug() << " dasher" << offset/64. << reverse << dashIndex;
|
||||||
|
stroker->patternOffset += delta;
|
||||||
|
stroker->patternOffset %= stroker->patternLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool on() const {
|
||||||
|
return (dashIndex + dashOn) & 1;
|
||||||
|
}
|
||||||
|
void adjust() {
|
||||||
|
offset += 64;
|
||||||
|
if (offset >= pattern[dashIndex]) {
|
||||||
|
++dashIndex;
|
||||||
|
dashIndex %= stroker->patternSize;
|
||||||
|
}
|
||||||
|
offset %= stroker->patternLength;
|
||||||
|
// qDebug() << "dasher.adjust" << offset/64. << dashIndex;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NoDasher {
|
||||||
|
NoDasher(QCosmeticStroker *, bool, int, int) {}
|
||||||
|
bool on() const { return true; }
|
||||||
|
void adjust(int = 0) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template<DrawPixel drawPixel, class Dasher>
|
||||||
|
static void drawLine(QCosmeticStroker *stroker, qreal x1, qreal y1, qreal x2, qreal y2, int caps);
|
||||||
|
template<DrawPixel drawPixel, class Dasher>
|
||||||
|
static void drawLineAA(QCosmeticStroker *stroker, qreal x1, qreal y1, qreal x2, qreal y2, int caps);
|
||||||
|
|
||||||
|
inline void drawPixel(QCosmeticStroker *stroker, int x, int y, int coverage)
|
||||||
|
{
|
||||||
|
int lastx = stroker->spans[stroker->current_span-1].x + stroker->spans[stroker->current_span-1].len ;
|
||||||
|
int lasty = stroker->spans[stroker->current_span-1].y;
|
||||||
|
|
||||||
|
if (stroker->current_span == QCosmeticStroker::NSPANS || y < lasty || (y == lasty && x < lastx)) {
|
||||||
|
stroker->blend(stroker->current_span, stroker->spans, &stroker->state->penData);
|
||||||
|
stroker->current_span = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
stroker->spans[stroker->current_span].x = ushort(x);
|
||||||
|
stroker->spans[stroker->current_span].len = 1;
|
||||||
|
stroker->spans[stroker->current_span].y = y;
|
||||||
|
stroker->spans[stroker->current_span].coverage = coverage*stroker->opacity >> 8;
|
||||||
|
++stroker->current_span;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void drawPixelARGB32(QCosmeticStroker *stroker, int x, int y, int coverage)
|
||||||
|
{
|
||||||
|
const QRect &cl = stroker->clip;
|
||||||
|
if (x < cl.x() || x > cl.right() || y < cl.y() || y > cl.bottom())
|
||||||
|
return;
|
||||||
|
|
||||||
|
int offset = x + stroker->ppl*y;
|
||||||
|
uint c = BYTE_MUL(stroker->color, coverage);
|
||||||
|
stroker->pixels[offset] = sourceOver(stroker->pixels[offset], c);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void drawPixelARGB32Opaque(QCosmeticStroker *stroker, int x, int y, int)
|
||||||
|
{
|
||||||
|
const QRect &cl = stroker->clip;
|
||||||
|
if (x < cl.x() || x > cl.right() || y < cl.y() || y > cl.bottom())
|
||||||
|
return;
|
||||||
|
|
||||||
|
int offset = x + stroker->ppl*y;
|
||||||
|
stroker->pixels[offset] = sourceOver(stroker->pixels[offset], stroker->color);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum StrokeSelection {
|
||||||
|
Aliased = 0,
|
||||||
|
AntiAliased = 1,
|
||||||
|
Solid = 0,
|
||||||
|
Dashed = 2,
|
||||||
|
RegularDraw = 0,
|
||||||
|
FastDraw = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
static StrokeLine strokeLine(int strokeSelection)
|
||||||
|
{
|
||||||
|
StrokeLine stroke;
|
||||||
|
|
||||||
|
switch (strokeSelection) {
|
||||||
|
case Aliased|Solid|RegularDraw:
|
||||||
|
stroke = &QT_PREPEND_NAMESPACE(drawLine)<drawPixel, NoDasher>;
|
||||||
|
break;
|
||||||
|
case Aliased|Solid|FastDraw:
|
||||||
|
stroke = &QT_PREPEND_NAMESPACE(drawLine)<drawPixelARGB32Opaque, NoDasher>;
|
||||||
|
break;
|
||||||
|
case Aliased|Dashed|RegularDraw:
|
||||||
|
stroke = &QT_PREPEND_NAMESPACE(drawLine)<drawPixel, Dasher>;
|
||||||
|
break;
|
||||||
|
case Aliased|Dashed|FastDraw:
|
||||||
|
stroke = &QT_PREPEND_NAMESPACE(drawLine)<drawPixelARGB32Opaque, Dasher>;
|
||||||
|
break;
|
||||||
|
case AntiAliased|Solid|RegularDraw:
|
||||||
|
stroke = &QT_PREPEND_NAMESPACE(drawLineAA)<drawPixel, NoDasher>;
|
||||||
|
break;
|
||||||
|
case AntiAliased|Solid|FastDraw:
|
||||||
|
stroke = &QT_PREPEND_NAMESPACE(drawLineAA)<drawPixelARGB32, NoDasher>;
|
||||||
|
break;
|
||||||
|
case AntiAliased|Dashed|RegularDraw:
|
||||||
|
stroke = &QT_PREPEND_NAMESPACE(drawLineAA)<drawPixel, Dasher>;
|
||||||
|
break;
|
||||||
|
case AntiAliased|Dashed|FastDraw:
|
||||||
|
stroke = &QT_PREPEND_NAMESPACE(drawLineAA)<drawPixelARGB32, Dasher>;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
stroke = 0;
|
||||||
|
}
|
||||||
|
return stroke;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QCosmeticStroker::setup()
|
||||||
|
{
|
||||||
|
blend = state->penData.blend;
|
||||||
|
if (state->clip && state->clip->enabled && state->clip->hasRectClip && !state->clip->clipRect.isEmpty()) {
|
||||||
|
clip &= state->clip->clipRect;
|
||||||
|
blend = state->penData.unclipped_blend;
|
||||||
|
}
|
||||||
|
|
||||||
|
int strokeSelection = 0;
|
||||||
|
if (blend == state->penData.unclipped_blend
|
||||||
|
&& state->penData.type == QSpanData::Solid
|
||||||
|
&& (state->penData.rasterBuffer->format == QImage::Format_ARGB32_Premultiplied
|
||||||
|
|| state->penData.rasterBuffer->format == QImage::Format_RGB32)
|
||||||
|
&& state->compositionMode() == QPainter::CompositionMode_SourceOver)
|
||||||
|
strokeSelection |= FastDraw;
|
||||||
|
|
||||||
|
if (state->renderHints & QPainter::Antialiasing)
|
||||||
|
strokeSelection |= AntiAliased;
|
||||||
|
|
||||||
|
const QVector<qreal> &penPattern = state->lastPen.dashPattern();
|
||||||
|
if (penPattern.isEmpty()) {
|
||||||
|
Q_ASSERT(!pattern && !reversePattern);
|
||||||
|
pattern = 0;
|
||||||
|
reversePattern = 0;
|
||||||
|
patternLength = 0;
|
||||||
|
patternSize = 0;
|
||||||
|
} else {
|
||||||
|
pattern = (int *)malloc(penPattern.size()*sizeof(int));
|
||||||
|
reversePattern = (int *)malloc(penPattern.size()*sizeof(int));
|
||||||
|
patternSize = penPattern.size();
|
||||||
|
|
||||||
|
patternLength = 0;
|
||||||
|
for (int i = 0; i < patternSize; ++i) {
|
||||||
|
patternLength += (int) qMax(1. , penPattern.at(i)*64.);
|
||||||
|
pattern[i] = patternLength;
|
||||||
|
}
|
||||||
|
patternLength = 0;
|
||||||
|
for (int i = 0; i < patternSize; ++i) {
|
||||||
|
patternLength += (int) qMax(1., penPattern.at(patternSize - 1 - i)*64.);
|
||||||
|
reversePattern[i] = patternLength;
|
||||||
|
}
|
||||||
|
strokeSelection |= Dashed;
|
||||||
|
// qDebug() << "setup: size=" << patternSize << "length=" << patternLength/64.;
|
||||||
|
}
|
||||||
|
|
||||||
|
stroke = strokeLine(strokeSelection);
|
||||||
|
|
||||||
|
qreal width = state->lastPen.widthF();
|
||||||
|
if (width == 0)
|
||||||
|
opacity = 256;
|
||||||
|
else if (state->lastPen.isCosmetic())
|
||||||
|
opacity = (int) 256*width;
|
||||||
|
else
|
||||||
|
opacity = (int) 256*width*state->txscale;
|
||||||
|
opacity = qBound(0, opacity, 256);
|
||||||
|
|
||||||
|
drawCaps = state->lastPen.capStyle() != Qt::FlatCap;
|
||||||
|
|
||||||
|
if (strokeSelection & FastDraw) {
|
||||||
|
color = INTERPOLATE_PIXEL_256(state->penData.solid.color, opacity, 0, 0);
|
||||||
|
QRasterBuffer *buffer = state->penData.rasterBuffer;
|
||||||
|
pixels = (uint *)buffer->buffer();
|
||||||
|
ppl = buffer->bytesPerLine()>>2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup FP clip bounds
|
||||||
|
xmin = clip.left() - 1;
|
||||||
|
xmax = clip.right() + 2;
|
||||||
|
ymin = clip.top() - 1;
|
||||||
|
ymax = clip.bottom() + 2;
|
||||||
|
|
||||||
|
lastPixel.x = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns true if the whole line gets clipped away
|
||||||
|
bool QCosmeticStroker::clipLine(qreal &x1, qreal &y1, qreal &x2, qreal &y2)
|
||||||
|
{
|
||||||
|
// basic/rough clipping is done in floating point coordinates to avoid
|
||||||
|
// integer overflow problems.
|
||||||
|
if (x1 < xmin) {
|
||||||
|
if (x2 <= xmin)
|
||||||
|
goto clipped;
|
||||||
|
y1 += (y2 - y1)/(x2 - x1) * (xmin - x1);
|
||||||
|
x1 = xmin;
|
||||||
|
} else if (x1 > xmax) {
|
||||||
|
if (x2 >= xmax)
|
||||||
|
goto clipped;
|
||||||
|
y1 += (y2 - y1)/(x2 - x1) * (xmax - x1);
|
||||||
|
x1 = xmax;
|
||||||
|
}
|
||||||
|
if (x2 < xmin) {
|
||||||
|
lastPixel.x = -1;
|
||||||
|
y2 += (y2 - y1)/(x2 - x1) * (xmin - x2);
|
||||||
|
x2 = xmin;
|
||||||
|
} else if (x2 > xmax) {
|
||||||
|
lastPixel.x = -1;
|
||||||
|
y2 += (y2 - y1)/(x2 - x1) * (xmax - x2);
|
||||||
|
x2 = xmax;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y1 < ymin) {
|
||||||
|
if (y2 <= ymin)
|
||||||
|
goto clipped;
|
||||||
|
x1 += (x2 - x1)/(y2 - y1) * (ymin - y1);
|
||||||
|
y1 = ymin;
|
||||||
|
} else if (y1 > ymax) {
|
||||||
|
if (y2 >= ymax)
|
||||||
|
goto clipped;
|
||||||
|
x1 += (x2 - x1)/(y2 - y1) * (ymax - y1);
|
||||||
|
y1 = ymax;
|
||||||
|
}
|
||||||
|
if (y2 < ymin) {
|
||||||
|
lastPixel.x = -1;
|
||||||
|
x2 += (x2 - x1)/(y2 - y1) * (ymin - y2);
|
||||||
|
y2 = ymin;
|
||||||
|
} else if (y2 > ymax) {
|
||||||
|
lastPixel.x = -1;
|
||||||
|
x2 += (x2 - x1)/(y2 - y1) * (ymax - y2);
|
||||||
|
y2 = ymax;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
clipped:
|
||||||
|
lastPixel.x = -1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void QCosmeticStroker::drawLine(const QPointF &p1, const QPointF &p2)
|
||||||
|
{
|
||||||
|
QPointF start = p1 * state->matrix;
|
||||||
|
QPointF end = p2 * state->matrix;
|
||||||
|
|
||||||
|
patternOffset = state->lastPen.dashOffset()*64;
|
||||||
|
lastPixel.x = -1;
|
||||||
|
|
||||||
|
stroke(this, start.x(), start.y(), end.x(), end.y(), drawCaps ? CapBegin|CapEnd : 0);
|
||||||
|
|
||||||
|
blend(current_span, spans, &state->penData);
|
||||||
|
current_span = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QCosmeticStroker::drawPoints(const QPoint *points, int num)
|
||||||
|
{
|
||||||
|
const QPoint *end = points + num;
|
||||||
|
while (points < end) {
|
||||||
|
QPointF p = QPointF(*points) * state->matrix;
|
||||||
|
drawPixel(this, qRound(p.x()), qRound(p.y()), 255);
|
||||||
|
++points;
|
||||||
|
}
|
||||||
|
|
||||||
|
blend(current_span, spans, &state->penData);
|
||||||
|
current_span = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QCosmeticStroker::drawPoints(const QPointF *points, int num)
|
||||||
|
{
|
||||||
|
const QPointF *end = points + num;
|
||||||
|
while (points < end) {
|
||||||
|
QPointF p = (*points) * state->matrix;
|
||||||
|
drawPixel(this, qRound(p.x()), qRound(p.y()), 255);
|
||||||
|
++points;
|
||||||
|
}
|
||||||
|
|
||||||
|
blend(current_span, spans, &state->penData);
|
||||||
|
current_span = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QCosmeticStroker::calculateLastPoint(qreal rx1, qreal ry1, qreal rx2, qreal ry2)
|
||||||
|
{
|
||||||
|
// this is basically the same code as used in the aliased stroke method,
|
||||||
|
// but it only determines the direction and last point of a line
|
||||||
|
//
|
||||||
|
// This is being used to have proper dropout control for closed contours
|
||||||
|
// by calculating the direction and last pixel of the last segment in the contour.
|
||||||
|
// the info is then used to perform dropout control when drawing the first line segment
|
||||||
|
// of the contour
|
||||||
|
lastPixel.x = -1;
|
||||||
|
lastPixel.y = -1;
|
||||||
|
|
||||||
|
if (clipLine(rx1, ry1, rx2, ry2))
|
||||||
|
return;
|
||||||
|
|
||||||
|
int x1 = toF26Dot6(rx1);
|
||||||
|
int y1 = toF26Dot6(ry1);
|
||||||
|
int x2 = toF26Dot6(rx2);
|
||||||
|
int y2 = toF26Dot6(ry2);
|
||||||
|
|
||||||
|
int dx = qAbs(x2 - x1);
|
||||||
|
int dy = qAbs(y2 - y1);
|
||||||
|
|
||||||
|
if (dx < dy) {
|
||||||
|
// vertical
|
||||||
|
bool swapped = false;
|
||||||
|
if (y1 > y2) {
|
||||||
|
swapped = true;
|
||||||
|
qSwap(y1, y2);
|
||||||
|
qSwap(x1, x2);
|
||||||
|
}
|
||||||
|
int xinc = F16Dot16FixedDiv(x2 - x1, y2 - y1);
|
||||||
|
int x = x1 << 10;
|
||||||
|
|
||||||
|
int y = (y1+32) >> 6;
|
||||||
|
int ys = (y2+32) >> 6;
|
||||||
|
|
||||||
|
if (y != ys) {
|
||||||
|
x += ( ((((y << 6) + 32 - y1))) * xinc ) >> 6;
|
||||||
|
|
||||||
|
if (swapped) {
|
||||||
|
lastPixel.x = x >> 16;
|
||||||
|
lastPixel.y = y;
|
||||||
|
lastDir = QCosmeticStroker::BottomToTop;
|
||||||
|
} else {
|
||||||
|
lastPixel.x = (x + (ys - y - 1)*xinc) >> 16;
|
||||||
|
lastPixel.y = ys - 1;
|
||||||
|
lastDir = QCosmeticStroker::TopToBottom;
|
||||||
|
}
|
||||||
|
lastAxisAligned = qAbs(xinc) < (1 << 14);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// horizontal
|
||||||
|
if (!dx)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool swapped = false;
|
||||||
|
if (x1 > x2) {
|
||||||
|
swapped = true;
|
||||||
|
qSwap(x1, x2);
|
||||||
|
qSwap(y1, y2);
|
||||||
|
}
|
||||||
|
int yinc = F16Dot16FixedDiv(y2 - y1, x2 - x1);
|
||||||
|
int y = y1 << 10;
|
||||||
|
|
||||||
|
int x = (x1+32) >> 6;
|
||||||
|
int xs = (x2+32) >> 6;
|
||||||
|
|
||||||
|
if (x != xs) {
|
||||||
|
y += ( ((((x << 6) + 32 - x1))) * yinc ) >> 6;
|
||||||
|
|
||||||
|
if (swapped) {
|
||||||
|
lastPixel.x = x;
|
||||||
|
lastPixel.y = y >> 16;
|
||||||
|
lastDir = QCosmeticStroker::RightToLeft;
|
||||||
|
} else {
|
||||||
|
lastPixel.x = xs - 1;
|
||||||
|
lastPixel.y = (y + (xs - x - 1)*yinc) >> 16;
|
||||||
|
lastDir = QCosmeticStroker::LeftToRight;
|
||||||
|
}
|
||||||
|
lastAxisAligned = qAbs(yinc) < (1 << 14);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// qDebug() << " moveTo: setting last pixel to x/y dir" << lastPixel.x << lastPixel.y << lastDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const QPainterPath::ElementType *subPath(const QPainterPath::ElementType *t, const QPainterPath::ElementType *end,
|
||||||
|
const qreal *points, bool *closed)
|
||||||
|
{
|
||||||
|
const QPainterPath::ElementType *start = t;
|
||||||
|
++t;
|
||||||
|
|
||||||
|
// find out if the subpath is closed
|
||||||
|
while (t < end) {
|
||||||
|
if (*t == QPainterPath::MoveToElement)
|
||||||
|
break;
|
||||||
|
++t;
|
||||||
|
}
|
||||||
|
|
||||||
|
int offset = t - start - 1;
|
||||||
|
// qDebug() << "subpath" << offset << points[0] << points[1] << points[2*offset] << points[2*offset+1];
|
||||||
|
*closed = (points[0] == points[2*offset] && points[1] == points[2*offset + 1]);
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QCosmeticStroker::drawPath(const QVectorPath &path)
|
||||||
|
{
|
||||||
|
// qDebug() << ">>>> drawpath" << path.convertToPainterPath()
|
||||||
|
// << "antialiasing:" << (bool)(state->renderHints & QPainter::Antialiasing) << " implicit close:" << path.hasImplicitClose();
|
||||||
|
if (path.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const qreal *points = path.points();
|
||||||
|
const QPainterPath::ElementType *type = path.elements();
|
||||||
|
|
||||||
|
if (type) {
|
||||||
|
const QPainterPath::ElementType *end = type + path.elementCount();
|
||||||
|
|
||||||
|
while (type < end) {
|
||||||
|
Q_ASSERT(type == path.elements() || *type == QPainterPath::MoveToElement);
|
||||||
|
|
||||||
|
QPointF p = QPointF(points[0], points[1]) * state->matrix;
|
||||||
|
QPointF movedTo = p;
|
||||||
|
patternOffset = state->lastPen.dashOffset()*64;
|
||||||
|
lastPixel.x = -1;
|
||||||
|
|
||||||
|
bool closed;
|
||||||
|
const QPainterPath::ElementType *e = subPath(type, end, points, &closed);
|
||||||
|
if (closed) {
|
||||||
|
const qreal *p = points + 2*(e-type);
|
||||||
|
calculateLastPoint(p[-4], p[-3], p[-2], p[-1]);
|
||||||
|
}
|
||||||
|
int caps = (!closed & drawCaps) ? CapBegin : NoCaps;
|
||||||
|
// qDebug() << "closed =" << closed << capString(caps);
|
||||||
|
|
||||||
|
points += 2;
|
||||||
|
++type;
|
||||||
|
|
||||||
|
while (type < e) {
|
||||||
|
QPointF p2 = QPointF(points[0], points[1]) * state->matrix;
|
||||||
|
switch (*type) {
|
||||||
|
case QPainterPath::MoveToElement:
|
||||||
|
Q_ASSERT(!"Logic error");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QPainterPath::LineToElement:
|
||||||
|
if (!closed && drawCaps && type == e - 1)
|
||||||
|
caps |= CapEnd;
|
||||||
|
stroke(this, p.x(), p.y(), p2.x(), p2.y(), caps);
|
||||||
|
p = p2;
|
||||||
|
points += 2;
|
||||||
|
++type;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QPainterPath::CurveToElement: {
|
||||||
|
if (!closed && drawCaps && type == e - 3)
|
||||||
|
caps |= CapEnd;
|
||||||
|
QPointF p3 = QPointF(points[2], points[3]) * state->matrix;
|
||||||
|
QPointF p4 = QPointF(points[4], points[5]) * state->matrix;
|
||||||
|
renderCubic(p, p2, p3, p4, caps);
|
||||||
|
p = p4;
|
||||||
|
type += 3;
|
||||||
|
points += 6;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QPainterPath::CurveToDataElement:
|
||||||
|
Q_ASSERT(!"QPainterPath::toSubpathPolygons(), bad element type");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
caps = NoCaps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // !type, simple polygon
|
||||||
|
QPointF p = QPointF(points[0], points[1]) * state->matrix;
|
||||||
|
QPointF movedTo = p;
|
||||||
|
patternOffset = state->lastPen.dashOffset()*64;
|
||||||
|
lastPixel.x = -1;
|
||||||
|
|
||||||
|
const qreal *end = points + 2*path.elementCount();
|
||||||
|
// handle closed path case
|
||||||
|
bool closed = path.hasImplicitClose() || (points[0] == end[-2] && points[1] == end[-1]);
|
||||||
|
int caps = (!closed & drawCaps) ? CapBegin : NoCaps;
|
||||||
|
if (closed)
|
||||||
|
calculateLastPoint(end[-2], end[-1], points[0], points[1]);
|
||||||
|
|
||||||
|
points += 2;
|
||||||
|
while (points < end) {
|
||||||
|
QPointF p2 = QPointF(points[0], points[1]) * state->matrix;
|
||||||
|
|
||||||
|
if (!closed && drawCaps && points == end - 2)
|
||||||
|
caps |= CapEnd;
|
||||||
|
|
||||||
|
stroke(this, p.x(), p.y(), p2.x(), p2.y(), caps);
|
||||||
|
|
||||||
|
p = p2;
|
||||||
|
points += 2;
|
||||||
|
caps = NoCaps;
|
||||||
|
}
|
||||||
|
if (path.hasImplicitClose())
|
||||||
|
stroke(this, p.x(), p.y(), movedTo.x(), movedTo.y(), NoCaps);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
blend(current_span, spans, &state->penData);
|
||||||
|
current_span = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QCosmeticStroker::renderCubic(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4, int caps)
|
||||||
|
{
|
||||||
|
// qDebug() << ">>>> renderCubic" << p1 << p2 << p3 << p4 << capString(caps);
|
||||||
|
const int maxSubDivisions = 6;
|
||||||
|
PointF points[3*maxSubDivisions + 4];
|
||||||
|
|
||||||
|
points[3].x = p1.x();
|
||||||
|
points[3].y = p1.y();
|
||||||
|
points[2].x = p2.x();
|
||||||
|
points[2].y = p2.y();
|
||||||
|
points[1].x = p3.x();
|
||||||
|
points[1].y = p3.y();
|
||||||
|
points[0].x = p4.x();
|
||||||
|
points[0].y = p4.y();
|
||||||
|
|
||||||
|
PointF *p = points;
|
||||||
|
int level = maxSubDivisions;
|
||||||
|
|
||||||
|
renderCubicSubdivision(p, level, caps);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void splitCubic(QCosmeticStroker::PointF *points)
|
||||||
|
{
|
||||||
|
const qreal half = .5;
|
||||||
|
qreal a, b, c, d;
|
||||||
|
|
||||||
|
points[6].x = points[3].x;
|
||||||
|
c = points[1].x;
|
||||||
|
d = points[2].x;
|
||||||
|
points[1].x = a = ( points[0].x + c ) * half;
|
||||||
|
points[5].x = b = ( points[3].x + d ) * half;
|
||||||
|
c = ( c + d ) * half;
|
||||||
|
points[2].x = a = ( a + c ) * half;
|
||||||
|
points[4].x = b = ( b + c ) * half;
|
||||||
|
points[3].x = ( a + b ) * half;
|
||||||
|
|
||||||
|
points[6].y = points[3].y;
|
||||||
|
c = points[1].y;
|
||||||
|
d = points[2].y;
|
||||||
|
points[1].y = a = ( points[0].y + c ) * half;
|
||||||
|
points[5].y = b = ( points[3].y + d ) * half;
|
||||||
|
c = ( c + d ) * half;
|
||||||
|
points[2].y = a = ( a + c ) * half;
|
||||||
|
points[4].y = b = ( b + c ) * half;
|
||||||
|
points[3].y = ( a + b ) * half;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QCosmeticStroker::renderCubicSubdivision(QCosmeticStroker::PointF *points, int level, int caps)
|
||||||
|
{
|
||||||
|
if (level) {
|
||||||
|
qreal dx = points[3].x - points[0].x;
|
||||||
|
qreal dy = points[3].y - points[0].y;
|
||||||
|
qreal len = ((qreal).25) * (qAbs(dx) + qAbs(dy));
|
||||||
|
|
||||||
|
if (qAbs(dx * (points[0].y - points[2].y) - dy * (points[0].x - points[2].x)) > len ||
|
||||||
|
qAbs(dx * (points[0].y - points[1].y) - dy * (points[0].x - points[1].x)) > len) {
|
||||||
|
splitCubic(points);
|
||||||
|
|
||||||
|
--level;
|
||||||
|
renderCubicSubdivision(points + 3, level, caps & CapBegin);
|
||||||
|
renderCubicSubdivision(points, level, caps & CapEnd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stroke(this, points[3].x, points[3].y, points[0].x, points[0].y, caps);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int swapCaps(int caps)
|
||||||
|
{
|
||||||
|
return ((caps & QCosmeticStroker::CapBegin) << 1) |
|
||||||
|
((caps & QCosmeticStroker::CapEnd) >> 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// adjust line by half a pixel
|
||||||
|
static inline void capAdjust(int caps, int &x1, int &x2, int &y, int yinc)
|
||||||
|
{
|
||||||
|
if (caps & QCosmeticStroker::CapBegin) {
|
||||||
|
x1 -= 32;
|
||||||
|
y -= yinc >> 1;
|
||||||
|
}
|
||||||
|
if (caps & QCosmeticStroker::CapEnd) {
|
||||||
|
x2 += 32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
The hard part about this is dropout control and avoiding douple drawing of points when
|
||||||
|
the drawing shifts from horizontal to vertical or back.
|
||||||
|
*/
|
||||||
|
template<DrawPixel drawPixel, class Dasher>
|
||||||
|
static void drawLine(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2, qreal ry2, int caps)
|
||||||
|
{
|
||||||
|
if (stroker->clipLine(rx1, ry1, rx2, ry2))
|
||||||
|
return;
|
||||||
|
|
||||||
|
static const int half = 32;
|
||||||
|
int x1 = toF26Dot6(rx1) + half;
|
||||||
|
int y1 = toF26Dot6(ry1) + half;
|
||||||
|
int x2 = toF26Dot6(rx2) + half;
|
||||||
|
int y2 = toF26Dot6(ry2) + half;
|
||||||
|
|
||||||
|
int dx = qAbs(x2 - x1);
|
||||||
|
int dy = qAbs(y2 - y1);
|
||||||
|
|
||||||
|
QCosmeticStroker::Point last = stroker->lastPixel;
|
||||||
|
|
||||||
|
// qDebug() << "stroke" << x1/64. << y1/64. << x2/64. << y2/64. << capString(caps);
|
||||||
|
|
||||||
|
if (dx < dy) {
|
||||||
|
// vertical
|
||||||
|
|
||||||
|
bool swapped = false;
|
||||||
|
if (y1 > y2) {
|
||||||
|
swapped = true;
|
||||||
|
qSwap(y1, y2);
|
||||||
|
qSwap(x1, x2);
|
||||||
|
caps = swapCaps(caps);
|
||||||
|
--x1; --x2; --y1; --y2;
|
||||||
|
}
|
||||||
|
int xinc = F16Dot16FixedDiv(x2 - x1, y2 - y1);
|
||||||
|
int x = x1 << 10;
|
||||||
|
|
||||||
|
capAdjust(caps, y1, y2, x, xinc);
|
||||||
|
|
||||||
|
int y = (y1+32) >> 6;
|
||||||
|
int ys = (y2+32) >> 6;
|
||||||
|
|
||||||
|
if (y != ys) {
|
||||||
|
x += ( ((((y << 6) + 32 - y1))) * xinc ) >> 6;
|
||||||
|
|
||||||
|
// calculate first and last pixel and perform dropout control
|
||||||
|
QCosmeticStroker::Direction dir = QCosmeticStroker::TopToBottom;
|
||||||
|
QCosmeticStroker::Point first;
|
||||||
|
first.x = x >> 16;
|
||||||
|
first.y = y;
|
||||||
|
last.x = (x + (ys - y - 1)*xinc) >> 16;
|
||||||
|
last.y = ys - 1;
|
||||||
|
if (swapped) {
|
||||||
|
qSwap(first, last);
|
||||||
|
dir = QCosmeticStroker::BottomToTop;
|
||||||
|
}
|
||||||
|
bool axisAligned = qAbs(xinc) < (1 << 14);
|
||||||
|
if (stroker->lastPixel.x >= 0) {
|
||||||
|
if (first.x == stroker->lastPixel.x &&
|
||||||
|
first.y == stroker->lastPixel.y) {
|
||||||
|
// remove duplicated pixel
|
||||||
|
if (swapped) {
|
||||||
|
--ys;
|
||||||
|
} else {
|
||||||
|
++y;
|
||||||
|
x += xinc;
|
||||||
|
}
|
||||||
|
} else if (stroker->lastDir != dir &&
|
||||||
|
(((axisAligned && stroker->lastAxisAligned) &&
|
||||||
|
stroker->lastPixel.x != first.x && stroker->lastPixel.y != first.y) ||
|
||||||
|
(qAbs(stroker->lastPixel.x - first.x) > 1 &&
|
||||||
|
qAbs(stroker->lastPixel.y - first.y) > 1))) {
|
||||||
|
// have a missing pixel, insert it
|
||||||
|
if (swapped) {
|
||||||
|
++ys;
|
||||||
|
} else {
|
||||||
|
--y;
|
||||||
|
x -= xinc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stroker->lastDir = dir;
|
||||||
|
stroker->lastAxisAligned = axisAligned;
|
||||||
|
|
||||||
|
Dasher dasher(stroker, swapped, y << 6, ys << 6);
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (dasher.on())
|
||||||
|
drawPixel(stroker, x >> 16, y, 255);
|
||||||
|
dasher.adjust();
|
||||||
|
x += xinc;
|
||||||
|
} while (++y < ys);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// horizontal
|
||||||
|
if (!dx)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool swapped = false;
|
||||||
|
if (x1 > x2) {
|
||||||
|
swapped = true;
|
||||||
|
qSwap(x1, x2);
|
||||||
|
qSwap(y1, y2);
|
||||||
|
caps = swapCaps(caps);
|
||||||
|
--x1; --x2; --y1; --y2;
|
||||||
|
}
|
||||||
|
int yinc = F16Dot16FixedDiv(y2 - y1, x2 - x1);
|
||||||
|
int y = y1 << 10;
|
||||||
|
|
||||||
|
capAdjust(caps, x1, x2, y, yinc);
|
||||||
|
|
||||||
|
int x = (x1+32) >> 6;
|
||||||
|
int xs = (x2+32) >> 6;
|
||||||
|
|
||||||
|
|
||||||
|
if (x != xs) {
|
||||||
|
y += ( ((((x << 6) + 32 - x1))) * yinc ) >> 6;
|
||||||
|
|
||||||
|
// calculate first and last pixel to perform dropout control
|
||||||
|
QCosmeticStroker::Direction dir = QCosmeticStroker::LeftToRight;
|
||||||
|
QCosmeticStroker::Point first;
|
||||||
|
first.x = x;
|
||||||
|
first.y = y >> 16;
|
||||||
|
last.x = xs - 1;
|
||||||
|
last.y = (y + (xs - x - 1)*yinc) >> 16;
|
||||||
|
if (swapped) {
|
||||||
|
qSwap(first, last);
|
||||||
|
dir = QCosmeticStroker::RightToLeft;
|
||||||
|
}
|
||||||
|
bool axisAligned = qAbs(yinc) < (1 << 14);
|
||||||
|
if (stroker->lastPixel.x >= 0) {
|
||||||
|
if (first.x == stroker->lastPixel.x && first.y == stroker->lastPixel.y) {
|
||||||
|
// remove duplicated pixel
|
||||||
|
if (swapped) {
|
||||||
|
--xs;
|
||||||
|
} else {
|
||||||
|
++x;
|
||||||
|
y += yinc;
|
||||||
|
}
|
||||||
|
} else if (stroker->lastDir != dir &&
|
||||||
|
(((axisAligned && stroker->lastAxisAligned) &&
|
||||||
|
stroker->lastPixel.x != first.x && stroker->lastPixel.y != first.y) ||
|
||||||
|
(qAbs(stroker->lastPixel.x - first.x) > 1 &&
|
||||||
|
qAbs(stroker->lastPixel.y - first.y) > 1))) {
|
||||||
|
// have a missing pixel, insert it
|
||||||
|
if (swapped) {
|
||||||
|
++xs;
|
||||||
|
} else {
|
||||||
|
--x;
|
||||||
|
y -= yinc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stroker->lastDir = dir;
|
||||||
|
stroker->lastAxisAligned = axisAligned;
|
||||||
|
|
||||||
|
Dasher dasher(stroker, swapped, x << 6, xs << 6);
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (dasher.on())
|
||||||
|
drawPixel(stroker, x, y >> 16, 255);
|
||||||
|
dasher.adjust();
|
||||||
|
y += yinc;
|
||||||
|
} while (++x < xs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stroker->lastPixel = last;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<DrawPixel drawPixel, class Dasher>
|
||||||
|
static void drawLineAA(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2, qreal ry2, int caps)
|
||||||
|
{
|
||||||
|
if (stroker->clipLine(rx1, ry1, rx2, ry2))
|
||||||
|
return;
|
||||||
|
|
||||||
|
int x1 = toF26Dot6(rx1);
|
||||||
|
int y1 = toF26Dot6(ry1);
|
||||||
|
int x2 = toF26Dot6(rx2);
|
||||||
|
int y2 = toF26Dot6(ry2);
|
||||||
|
|
||||||
|
int dx = x2 - x1;
|
||||||
|
int dy = y2 - y1;
|
||||||
|
|
||||||
|
if (qAbs(dx) < qAbs(dy)) {
|
||||||
|
// vertical
|
||||||
|
|
||||||
|
int xinc = F16Dot16FixedDiv(dx, dy);
|
||||||
|
|
||||||
|
bool swapped = false;
|
||||||
|
if (y1 > y2) {
|
||||||
|
qSwap(y1, y2);
|
||||||
|
qSwap(x1, x2);
|
||||||
|
swapped = true;
|
||||||
|
caps = swapCaps(caps);
|
||||||
|
}
|
||||||
|
|
||||||
|
int x = (x1 - 32) << 10;
|
||||||
|
x -= ( ((y1 & 63) - 32) * xinc ) >> 6;
|
||||||
|
|
||||||
|
capAdjust(caps, y1, y2, x, xinc);
|
||||||
|
|
||||||
|
Dasher dasher(stroker, swapped, y1, y2);
|
||||||
|
|
||||||
|
int y = y1 >> 6;
|
||||||
|
int ys = y2 >> 6;
|
||||||
|
|
||||||
|
int alphaStart, alphaEnd;
|
||||||
|
if (y == ys) {
|
||||||
|
alphaStart = y2 - y1;
|
||||||
|
Q_ASSERT(alphaStart >= 0 && alphaStart < 64);
|
||||||
|
alphaEnd = 0;
|
||||||
|
} else {
|
||||||
|
alphaStart = 64 - (y1 & 63);
|
||||||
|
alphaEnd = (y2 & 63);
|
||||||
|
}
|
||||||
|
// qDebug() << "vertical" << x1/64. << y1/64. << x2/64. << y2/64.;
|
||||||
|
// qDebug() << " x=" << x << "dx=" << dx << "xi=" << (x>>16) << "xsi=" << ((x+(ys-y)*dx)>>16) << "y=" << y << "ys=" << ys;
|
||||||
|
|
||||||
|
// draw first pixel
|
||||||
|
if (dasher.on()) {
|
||||||
|
uint alpha = (quint8)(x >> 8);
|
||||||
|
drawPixel(stroker, x>>16, y, (255-alpha) * alphaStart >> 6);
|
||||||
|
drawPixel(stroker, (x>>16) + 1, y, alpha * alphaStart >> 6);
|
||||||
|
}
|
||||||
|
dasher.adjust();
|
||||||
|
x += xinc;
|
||||||
|
++y;
|
||||||
|
if (y < ys) {
|
||||||
|
do {
|
||||||
|
if (dasher.on()) {
|
||||||
|
uint alpha = (quint8)(x >> 8);
|
||||||
|
drawPixel(stroker, x>>16, y, (255-alpha));
|
||||||
|
drawPixel(stroker, (x>>16) + 1, y, alpha);
|
||||||
|
}
|
||||||
|
dasher.adjust();
|
||||||
|
x += xinc;
|
||||||
|
} while (++y < ys);
|
||||||
|
}
|
||||||
|
// draw last pixel
|
||||||
|
if (alphaEnd && dasher.on()) {
|
||||||
|
uint alpha = (quint8)(x >> 8);
|
||||||
|
drawPixel(stroker, x>>16, y, (255-alpha) * alphaEnd >> 6);
|
||||||
|
drawPixel(stroker, (x>>16) + 1, y, alpha * alphaEnd >> 6);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// horizontal
|
||||||
|
if (!dx)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int yinc = F16Dot16FixedDiv(dy, dx);
|
||||||
|
|
||||||
|
bool swapped = false;
|
||||||
|
if (x1 > x2) {
|
||||||
|
qSwap(x1, x2);
|
||||||
|
qSwap(y1, y2);
|
||||||
|
swapped = true;
|
||||||
|
caps = swapCaps(caps);
|
||||||
|
}
|
||||||
|
|
||||||
|
int y = (y1 - 32) << 10;
|
||||||
|
y -= ( ((x1 & 63) - 32) * yinc ) >> 6;
|
||||||
|
|
||||||
|
capAdjust(caps, x1, x2, y, yinc);
|
||||||
|
|
||||||
|
Dasher dasher(stroker, swapped, x1, x2);
|
||||||
|
|
||||||
|
int x = x1 >> 6;
|
||||||
|
int xs = x2 >> 6;
|
||||||
|
|
||||||
|
// qDebug() << "horizontal" << x1/64. << y1/64. << x2/64. << y2/64.;
|
||||||
|
// qDebug() << " y=" << y << "dy=" << dy << "x=" << x << "xs=" << xs << "yi=" << (y>>16) << "ysi=" << ((y+(xs-x)*dy)>>16);
|
||||||
|
int alphaStart, alphaEnd;
|
||||||
|
if (x == xs) {
|
||||||
|
alphaStart = x2 - x1;
|
||||||
|
Q_ASSERT(alphaStart >= 0 && alphaStart < 64);
|
||||||
|
alphaEnd = 0;
|
||||||
|
} else {
|
||||||
|
alphaStart = 64 - (x1 & 63);
|
||||||
|
alphaEnd = (x2 & 63);
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw first pixel
|
||||||
|
if (dasher.on()) {
|
||||||
|
uint alpha = (quint8)(y >> 8);
|
||||||
|
drawPixel(stroker, x, y>>16, (255-alpha) * alphaStart >> 6);
|
||||||
|
drawPixel(stroker, x, (y>>16) + 1, alpha * alphaStart >> 6);
|
||||||
|
}
|
||||||
|
dasher.adjust();
|
||||||
|
y += yinc;
|
||||||
|
++x;
|
||||||
|
// draw line
|
||||||
|
if (x < xs) {
|
||||||
|
do {
|
||||||
|
if (dasher.on()) {
|
||||||
|
uint alpha = (quint8)(y >> 8);
|
||||||
|
drawPixel(stroker, x, y>>16, (255-alpha));
|
||||||
|
drawPixel(stroker, x, (y>>16) + 1, alpha);
|
||||||
|
}
|
||||||
|
dasher.adjust();
|
||||||
|
y += yinc;
|
||||||
|
} while (++x < xs);
|
||||||
|
}
|
||||||
|
// draw last pixel
|
||||||
|
if (alphaEnd && dasher.on()) {
|
||||||
|
uint alpha = (quint8)(y >> 8);
|
||||||
|
drawPixel(stroker, x, y>>16, (255-alpha) * alphaEnd >> 6);
|
||||||
|
drawPixel(stroker, x, (y>>16) + 1, alpha * alphaEnd >> 6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QT_END_NAMESPACE
|
111
src/gui/painting/qcosmeticstroker_p.h
Normal file
111
src/gui/painting/qcosmeticstroker_p.h
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
#ifndef QCOSMETICSTROKER_P_H
|
||||||
|
#define QCOSMETICSTROKER_P_H
|
||||||
|
|
||||||
|
#include <private/qdrawhelper_p.h>
|
||||||
|
#include <private/qvectorpath_p.h>
|
||||||
|
#include <private/qpaintengine_raster_p.h>
|
||||||
|
#include <qpen.h>
|
||||||
|
|
||||||
|
QT_BEGIN_HEADER
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
QT_MODULE(Gui)
|
||||||
|
|
||||||
|
class QCosmeticStroker;
|
||||||
|
|
||||||
|
|
||||||
|
typedef void (*StrokeLine)(QCosmeticStroker *stroker, qreal x1, qreal y1, qreal x2, qreal y2, int caps);
|
||||||
|
|
||||||
|
class QCosmeticStroker
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Point {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
};
|
||||||
|
struct PointF {
|
||||||
|
qreal x;
|
||||||
|
qreal y;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Caps {
|
||||||
|
NoCaps = 0,
|
||||||
|
CapBegin = 0x1,
|
||||||
|
CapEnd = 0x2,
|
||||||
|
};
|
||||||
|
|
||||||
|
// used to avoid drop outs or duplicated points
|
||||||
|
enum Direction {
|
||||||
|
TopToBottom,
|
||||||
|
BottomToTop,
|
||||||
|
LeftToRight,
|
||||||
|
RightToLeft
|
||||||
|
};
|
||||||
|
|
||||||
|
QCosmeticStroker(QRasterPaintEngineState *s, const QRect &dr)
|
||||||
|
: state(s),
|
||||||
|
clip(dr),
|
||||||
|
pattern(0),
|
||||||
|
reversePattern(0),
|
||||||
|
patternSize(0),
|
||||||
|
patternLength(0),
|
||||||
|
patternOffset(0),
|
||||||
|
current_span(0),
|
||||||
|
lastDir(LeftToRight),
|
||||||
|
lastAxisAligned(false)
|
||||||
|
{ setup(); }
|
||||||
|
~QCosmeticStroker() { free(pattern); free(reversePattern); }
|
||||||
|
void drawLine(const QPointF &p1, const QPointF &p2);
|
||||||
|
void drawPath(const QVectorPath &path);
|
||||||
|
void drawPoints(const QPoint *points, int num);
|
||||||
|
void drawPoints(const QPointF *points, int num);
|
||||||
|
|
||||||
|
|
||||||
|
QRasterPaintEngineState *state;
|
||||||
|
QRect clip;
|
||||||
|
// clip bounds in real
|
||||||
|
qreal xmin, xmax;
|
||||||
|
qreal ymin, ymax;
|
||||||
|
|
||||||
|
StrokeLine stroke;
|
||||||
|
bool drawCaps;
|
||||||
|
|
||||||
|
int *pattern;
|
||||||
|
int *reversePattern;
|
||||||
|
int patternSize;
|
||||||
|
int patternLength;
|
||||||
|
int patternOffset;
|
||||||
|
|
||||||
|
enum { NSPANS = 255 };
|
||||||
|
QT_FT_Span spans[NSPANS];
|
||||||
|
int current_span;
|
||||||
|
ProcessSpans blend;
|
||||||
|
|
||||||
|
int opacity;
|
||||||
|
|
||||||
|
uint color;
|
||||||
|
uint *pixels;
|
||||||
|
int ppl;
|
||||||
|
|
||||||
|
Direction lastDir;
|
||||||
|
Point lastPixel;
|
||||||
|
bool lastAxisAligned;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setup();
|
||||||
|
|
||||||
|
void renderCubic(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4, int caps);
|
||||||
|
void renderCubicSubdivision(PointF *points, int level, int caps);
|
||||||
|
// used for closed subpaths
|
||||||
|
void calculateLastPoint(qreal rx1, qreal ry1, qreal rx2, qreal ry2);
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool clipLine(qreal &x1, qreal &y1, qreal &x2, qreal &y2);
|
||||||
|
};
|
||||||
|
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
QT_END_HEADER
|
||||||
|
|
||||||
|
#endif // QCOSMETICLINE_H
|
File diff suppressed because it is too large
Load Diff
@ -196,9 +196,6 @@ public:
|
|||||||
void stroke(const QVectorPath &path, const QPen &pen);
|
void stroke(const QVectorPath &path, const QPen &pen);
|
||||||
void fill(const QVectorPath &path, const QBrush &brush);
|
void fill(const QVectorPath &path, const QBrush &brush);
|
||||||
|
|
||||||
void strokePolygonCosmetic(const QPoint *pts, int pointCount, PolygonDrawMode mode);
|
|
||||||
void strokePolygonCosmetic(const QPointF *pt, int pointCount, PolygonDrawMode mode);
|
|
||||||
|
|
||||||
void clip(const QVectorPath &path, Qt::ClipOperation op);
|
void clip(const QVectorPath &path, Qt::ClipOperation op);
|
||||||
void clip(const QRect &rect, Qt::ClipOperation op);
|
void clip(const QRect &rect, Qt::ClipOperation op);
|
||||||
void clip(const QRegion ®ion, Qt::ClipOperation op);
|
void clip(const QRegion ®ion, Qt::ClipOperation op);
|
||||||
@ -328,8 +325,6 @@ public:
|
|||||||
bool isUnclipped_normalized(const QRect &rect) const;
|
bool isUnclipped_normalized(const QRect &rect) const;
|
||||||
bool isUnclipped(const QRect &rect, int penWidth) const;
|
bool isUnclipped(const QRect &rect, int penWidth) const;
|
||||||
bool isUnclipped(const QRectF &rect, int penWidth) const;
|
bool isUnclipped(const QRectF &rect, int penWidth) const;
|
||||||
ProcessSpans getPenFunc(const QRect &rect, const QSpanData *data) const;
|
|
||||||
ProcessSpans getPenFunc(const QRectF &rect, const QSpanData *data) const;
|
|
||||||
ProcessSpans getBrushFunc(const QRect &rect, const QSpanData *data) const;
|
ProcessSpans getBrushFunc(const QRect &rect, const QSpanData *data) const;
|
||||||
ProcessSpans getBrushFunc(const QRectF &rect, const QSpanData *data) const;
|
ProcessSpans getBrushFunc(const QRectF &rect, const QSpanData *data) const;
|
||||||
|
|
||||||
|
@ -831,7 +831,7 @@ void QPaintEngineEx::drawEllipse(const QRectF &r)
|
|||||||
|
|
||||||
int point_count = 0;
|
int point_count = 0;
|
||||||
x.points[0] = qt_curves_for_arc(r, 0, -360, x.points + 1, &point_count);
|
x.points[0] = qt_curves_for_arc(r, 0, -360, x.points + 1, &point_count);
|
||||||
QVectorPath vp((qreal *) pts, point_count, qpaintengineex_ellipse_types, QVectorPath::EllipseHint);
|
QVectorPath vp((qreal *) pts, point_count + 1, qpaintengineex_ellipse_types, QVectorPath::EllipseHint);
|
||||||
draw(vp);
|
draw(vp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -651,7 +651,12 @@ void QLineControl::internalSetText(const QString &txt, int pos, bool edited)
|
|||||||
m_modifiedState = m_undoState = 0;
|
m_modifiedState = m_undoState = 0;
|
||||||
m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
|
m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
|
||||||
m_textDirty = (oldText != m_text);
|
m_textDirty = (oldText != m_text);
|
||||||
finishChange(-1, true, edited);
|
bool changed = finishChange(-1, true, edited);
|
||||||
|
|
||||||
|
#ifndef QT_NO_ACCESSIBILITY
|
||||||
|
if (changed)
|
||||||
|
QAccessible::updateAccessibility(parent(), 0, QAccessible::TextUpdated);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1238,6 +1243,9 @@ void QLineControl::emitCursorPositionChanged()
|
|||||||
const int oldLast = m_lastCursorPos;
|
const int oldLast = m_lastCursorPos;
|
||||||
m_lastCursorPos = m_cursor;
|
m_lastCursorPos = m_cursor;
|
||||||
cursorPositionChanged(oldLast, m_cursor);
|
cursorPositionChanged(oldLast, m_cursor);
|
||||||
|
#ifndef QT_NO_ACCESSIBILITY
|
||||||
|
QAccessible::updateAccessibility(parent(), 0, QAccessible::TextCaretMoved);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,10 +61,10 @@
|
|||||||
#include "QtGui/qtextlayout.h"
|
#include "QtGui/qtextlayout.h"
|
||||||
#include "QtGui/qstyleoption.h"
|
#include "QtGui/qstyleoption.h"
|
||||||
#include "QtCore/qpointer.h"
|
#include "QtCore/qpointer.h"
|
||||||
#include "QtGui/qlineedit.h"
|
|
||||||
#include "QtGui/qclipboard.h"
|
#include "QtGui/qclipboard.h"
|
||||||
#include "QtCore/qpoint.h"
|
#include "QtCore/qpoint.h"
|
||||||
#include "QtGui/qcompleter.h"
|
#include "QtGui/qcompleter.h"
|
||||||
|
#include "QtGui/qaccessible.h"
|
||||||
|
|
||||||
QT_BEGIN_HEADER
|
QT_BEGIN_HEADER
|
||||||
|
|
||||||
|
@ -153,6 +153,7 @@ void QLineEditPrivate::init(const QString& txt)
|
|||||||
{
|
{
|
||||||
Q_Q(QLineEdit);
|
Q_Q(QLineEdit);
|
||||||
control = new QLineControl(txt);
|
control = new QLineControl(txt);
|
||||||
|
control->setParent(q);
|
||||||
control->setFont(q->font());
|
control->setFont(q->font());
|
||||||
QObject::connect(control, SIGNAL(textChanged(QString)),
|
QObject::connect(control, SIGNAL(textChanged(QString)),
|
||||||
q, SIGNAL(textChanged(QString)));
|
q, SIGNAL(textChanged(QString)));
|
||||||
|
@ -84,7 +84,6 @@ public:
|
|||||||
|
|
||||||
~QLineEditPrivate()
|
~QLineEditPrivate()
|
||||||
{
|
{
|
||||||
delete control;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QLineControl *control;
|
QLineControl *control;
|
||||||
|
@ -103,7 +103,7 @@ SUBDIRS=\
|
|||||||
qlistview \
|
qlistview \
|
||||||
qlistwidget \
|
qlistwidget \
|
||||||
qlocale \
|
qlocale \
|
||||||
#qlocalsocket \ # FIXME: uses qtscript, shouldn't be in qtbase
|
#qlocalsocket \ # FIXME: uses qtscript (QTBUG-19242)
|
||||||
qmacstyle \
|
qmacstyle \
|
||||||
qmainwindow \
|
qmainwindow \
|
||||||
qmatrixnxn \
|
qmatrixnxn \
|
||||||
|
@ -3,7 +3,7 @@ SUBDIRS=\
|
|||||||
compiler \
|
compiler \
|
||||||
headersclean \
|
headersclean \
|
||||||
maketestselftest \
|
maketestselftest \
|
||||||
#moc \ # FIXME: cannot be built as part of qtbase, since it depends on qtsvg
|
#moc \ # FIXME: uses qtsvg (QTBUG-19243)
|
||||||
uic \
|
uic \
|
||||||
qmake \
|
qmake \
|
||||||
rcc \
|
rcc \
|
||||||
|
@ -10,8 +10,7 @@ SUBDIRS=\
|
|||||||
qalgorithms \
|
qalgorithms \
|
||||||
qcombobox \
|
qcombobox \
|
||||||
qcssparser \
|
qcssparser \
|
||||||
#qdatastream \ # FIXME: cannot be enabled by default in qtbase,
|
#qdatastream \ # FIXME: uses qtsvg (QTBUG-19244)
|
||||||
# since it depends on qtsvg
|
|
||||||
qdir \
|
qdir \
|
||||||
qfocusevent \
|
qfocusevent \
|
||||||
qimage \
|
qimage \
|
||||||
|
@ -1091,6 +1091,9 @@ void tst_QGraphicsAnchorLayout::setSpacing()
|
|||||||
#ifdef Q_WS_MAC
|
#ifdef Q_WS_MAC
|
||||||
QTest::qWait(200);
|
QTest::qWait(200);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// 21x21
|
||||||
|
QCOMPARE(p->size(), QSizeF(41, 41));
|
||||||
QCOMPARE(a->geometry(), QRectF(0, 0, 20, 20));
|
QCOMPARE(a->geometry(), QRectF(0, 0, 20, 20));
|
||||||
QCOMPARE(b->geometry(), QRectF(21, 0, 20, 20));
|
QCOMPARE(b->geometry(), QRectF(21, 0, 20, 20));
|
||||||
QCOMPARE(c->geometry(), QRectF(0, 21, 41, 20));
|
QCOMPARE(c->geometry(), QRectF(0, 21, 41, 20));
|
||||||
|
@ -62,6 +62,7 @@ private slots:
|
|||||||
void compressLayoutRequest();
|
void compressLayoutRequest();
|
||||||
void automaticReparenting();
|
void automaticReparenting();
|
||||||
void verifyActivate();
|
void verifyActivate();
|
||||||
|
void invalidate();
|
||||||
void constructors();
|
void constructors();
|
||||||
void alternativeLayoutItems();
|
void alternativeLayoutItems();
|
||||||
void ownership();
|
void ownership();
|
||||||
@ -95,6 +96,14 @@ void tst_QGraphicsLayout::sizeHints()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum FunctionType {
|
||||||
|
SetGeometry = 0,
|
||||||
|
Invalidate,
|
||||||
|
NumFunctionTypes
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class TestGraphicsWidget : public QGraphicsWidget {
|
class TestGraphicsWidget : public QGraphicsWidget {
|
||||||
public:
|
public:
|
||||||
TestGraphicsWidget(QGraphicsWidget *parent = 0) : QGraphicsWidget(parent)
|
TestGraphicsWidget(QGraphicsWidget *parent = 0) : QGraphicsWidget(parent)
|
||||||
@ -108,9 +117,28 @@ public:
|
|||||||
int eventCount(QEvent::Type type) {
|
int eventCount(QEvent::Type type) {
|
||||||
return m_eventCount.value(int(type));
|
return m_eventCount.value(int(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearEventCount() {
|
void clearEventCount() {
|
||||||
m_eventCount.clear();
|
m_eventCount.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clearCounters() {
|
||||||
|
m_eventCount.clear();
|
||||||
|
functionCount.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setGeometry(const QRectF &rect)
|
||||||
|
{
|
||||||
|
QGraphicsWidget::setGeometry(rect);
|
||||||
|
++(functionCount[SetGeometry]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void callUpdateGeometry()
|
||||||
|
{
|
||||||
|
// updateGeometry() is protected
|
||||||
|
QGraphicsWidget::updateGeometry();
|
||||||
|
}
|
||||||
|
QMap<FunctionType, int> functionCount;
|
||||||
private:
|
private:
|
||||||
QMap<int, int> m_eventCount;
|
QMap<int, int> m_eventCount;
|
||||||
};
|
};
|
||||||
@ -122,6 +150,8 @@ void tst_QGraphicsLayout::compressLayoutRequest()
|
|||||||
TestGraphicsWidget *tw = new TestGraphicsWidget();
|
TestGraphicsWidget *tw = new TestGraphicsWidget();
|
||||||
scene.addItem(tw);
|
scene.addItem(tw);
|
||||||
view.show();
|
view.show();
|
||||||
|
|
||||||
|
QTest::qWaitForWindowShown(&view);
|
||||||
QGraphicsLinearLayout *lout = new QGraphicsLinearLayout(tw);
|
QGraphicsLinearLayout *lout = new QGraphicsLinearLayout(tw);
|
||||||
for (int i = 0; i < 4; ++i) {
|
for (int i = 0; i < 4; ++i) {
|
||||||
QGraphicsWidget *gw = new QGraphicsWidget(tw);
|
QGraphicsWidget *gw = new QGraphicsWidget(tw);
|
||||||
@ -217,17 +247,27 @@ class TestLayout : public QGraphicsLinearLayout
|
|||||||
TestLayout(QGraphicsLayoutItem *parent = 0)
|
TestLayout(QGraphicsLayoutItem *parent = 0)
|
||||||
: QGraphicsLinearLayout(parent)
|
: QGraphicsLinearLayout(parent)
|
||||||
{
|
{
|
||||||
m_count = 0;
|
setContentsMargins(0,0,0,0);
|
||||||
|
setSpacing(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setGeometry(const QRectF &rect) {
|
void setGeometry(const QRectF &rect)
|
||||||
|
{
|
||||||
++m_count;
|
++(functionCount[SetGeometry]);
|
||||||
QGraphicsLinearLayout::setGeometry(rect);
|
QGraphicsLinearLayout::setGeometry(rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void invalidate()
|
||||||
|
{
|
||||||
|
++(functionCount[Invalidate]);
|
||||||
|
QGraphicsLinearLayout::invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
int m_count;
|
void clearCounters() {
|
||||||
|
functionCount.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<FunctionType, int> functionCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
void tst_QGraphicsLayout::verifyActivate()
|
void tst_QGraphicsLayout::verifyActivate()
|
||||||
@ -242,15 +282,280 @@ void tst_QGraphicsLayout::verifyActivate()
|
|||||||
lout->addItem(w);
|
lout->addItem(w);
|
||||||
window->setLayout(lout);
|
window->setLayout(lout);
|
||||||
|
|
||||||
QCOMPARE(lout->m_count, 0);
|
QCOMPARE(lout->functionCount[SetGeometry], 0);
|
||||||
window->setVisible(false);
|
window->setVisible(false);
|
||||||
QCOMPARE(lout->m_count, 0);
|
QCOMPARE(lout->functionCount[SetGeometry], 0);
|
||||||
window->setVisible(true);
|
window->setVisible(true);
|
||||||
// on polish or the first time a widget is shown, the widget is resized.
|
// on polish or the first time a widget is shown, the widget is resized.
|
||||||
QCOMPARE(lout->m_count, 1);
|
QCOMPARE(lout->functionCount[SetGeometry], 1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void clearAllCounters(TestGraphicsWidget *widget)
|
||||||
|
{
|
||||||
|
if (!widget)
|
||||||
|
return;
|
||||||
|
widget->clearCounters();
|
||||||
|
TestLayout *layout = static_cast<TestLayout *>(widget->layout());
|
||||||
|
if (layout) {
|
||||||
|
layout->clearCounters();
|
||||||
|
for (int i = layout->count() - 1; i >=0; --i) {
|
||||||
|
QGraphicsLayoutItem *item = layout->itemAt(i);
|
||||||
|
if (item->isLayout()) {
|
||||||
|
// ### Not used ATM
|
||||||
|
//TestLayout *lay = static_cast<TestLayout*>(static_cast<QGraphicsLayout*>(item));
|
||||||
|
//clearAllCounters(lay);
|
||||||
|
} else {
|
||||||
|
TestGraphicsWidget *wid = static_cast<TestGraphicsWidget *>(item);
|
||||||
|
clearAllCounters(wid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void activateAndReset(TestGraphicsWidget *widget)
|
||||||
|
{
|
||||||
|
QApplication::sendPostedEvents();
|
||||||
|
QApplication::processEvents();
|
||||||
|
if (widget->layout())
|
||||||
|
widget->layout()->activate();
|
||||||
|
clearAllCounters(widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void tst_QGraphicsLayout::invalidate()
|
||||||
|
{
|
||||||
|
QGraphicsLayout::setInstantInvalidatePropagation(true);
|
||||||
|
QGraphicsScene scene;
|
||||||
|
QGraphicsView view(&scene);
|
||||||
|
|
||||||
|
TestGraphicsWidget *a = new TestGraphicsWidget;
|
||||||
|
a->setData(0, QString("a"));
|
||||||
|
scene.addItem(a);
|
||||||
|
TestLayout *alay = new TestLayout(a);
|
||||||
|
TestGraphicsWidget *b = new TestGraphicsWidget;
|
||||||
|
b->setData(0, QString("b"));
|
||||||
|
alay->addItem(b);
|
||||||
|
TestLayout *blay = new TestLayout(b);
|
||||||
|
TestGraphicsWidget *e = new TestGraphicsWidget;
|
||||||
|
e->setData(0, QString("e"));
|
||||||
|
blay->addItem(e);
|
||||||
|
|
||||||
|
|
||||||
|
TestGraphicsWidget *c = new TestGraphicsWidget;
|
||||||
|
c->setData(0, QString("c"));
|
||||||
|
alay->addItem(c);
|
||||||
|
TestLayout *clay = new TestLayout(c);
|
||||||
|
TestGraphicsWidget *f = new TestGraphicsWidget;
|
||||||
|
f->setData(0, QString("f"));
|
||||||
|
clay->addItem(f);
|
||||||
|
|
||||||
|
TestGraphicsWidget *d = new TestGraphicsWidget;
|
||||||
|
d->setData(0, QString("d"));
|
||||||
|
alay->addItem(d);
|
||||||
|
TestLayout *dlay = new TestLayout(d);
|
||||||
|
TestGraphicsWidget *g = new TestGraphicsWidget;
|
||||||
|
g->setData(0, QString("g"));
|
||||||
|
dlay->addItem(g);
|
||||||
|
|
||||||
|
view.show();
|
||||||
|
|
||||||
|
{
|
||||||
|
clearAllCounters(a);
|
||||||
|
|
||||||
|
QCoreApplication::sendPostedEvents();
|
||||||
|
QCoreApplication::processEvents();
|
||||||
|
|
||||||
|
alay->activate();
|
||||||
|
QCOMPARE(alay->isActivated(), true);
|
||||||
|
QCOMPARE(blay->isActivated(), true);
|
||||||
|
QCOMPARE(clay->isActivated(), true);
|
||||||
|
QCOMPARE(dlay->isActivated(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
clearAllCounters(a);
|
||||||
|
e->callUpdateGeometry();
|
||||||
|
QCOMPARE(alay->isActivated(), false);
|
||||||
|
QCOMPARE(blay->isActivated(), false);
|
||||||
|
QCOMPARE(clay->isActivated(), true);
|
||||||
|
QCOMPARE(dlay->isActivated(), true);
|
||||||
|
QCOMPARE(a->eventCount(QEvent::LayoutRequest), 0);
|
||||||
|
QCOMPARE(b->eventCount(QEvent::LayoutRequest), 0);
|
||||||
|
QCOMPARE(c->eventCount(QEvent::LayoutRequest), 0);
|
||||||
|
QCOMPARE(d->eventCount(QEvent::LayoutRequest), 0);
|
||||||
|
|
||||||
|
// should only invalidate ascendants of e
|
||||||
|
QCOMPARE(blay->functionCount[Invalidate], 1);
|
||||||
|
QCOMPARE(alay->functionCount[Invalidate], 1);
|
||||||
|
// not siblings
|
||||||
|
QCOMPARE(clay->functionCount[Invalidate], 0);
|
||||||
|
QCOMPARE(dlay->functionCount[Invalidate], 0);
|
||||||
|
|
||||||
|
QApplication::sendPostedEvents();
|
||||||
|
QCOMPARE(a->eventCount(QEvent::LayoutRequest), 1);
|
||||||
|
QCOMPARE(b->eventCount(QEvent::LayoutRequest), 1);
|
||||||
|
QCOMPARE(c->eventCount(QEvent::LayoutRequest), 0);
|
||||||
|
QCOMPARE(d->eventCount(QEvent::LayoutRequest), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
activateAndReset(a);
|
||||||
|
f->callUpdateGeometry();
|
||||||
|
QCOMPARE(alay->isActivated(), false);
|
||||||
|
QCOMPARE(blay->isActivated(), true);
|
||||||
|
QCOMPARE(clay->isActivated(), false);
|
||||||
|
QCOMPARE(dlay->isActivated(), true);
|
||||||
|
|
||||||
|
QCoreApplication::sendPostedEvents();
|
||||||
|
QCOMPARE(a->eventCount(QEvent::LayoutRequest), 1);
|
||||||
|
QCOMPARE(b->eventCount(QEvent::LayoutRequest), 0);
|
||||||
|
QCOMPARE(c->eventCount(QEvent::LayoutRequest), 1);
|
||||||
|
QCOMPARE(d->eventCount(QEvent::LayoutRequest), 0);
|
||||||
|
|
||||||
|
QCOMPARE(a->functionCount[SetGeometry], 1);
|
||||||
|
QCOMPARE(alay->functionCount[SetGeometry], 1);
|
||||||
|
|
||||||
|
QCOMPARE(b->functionCount[SetGeometry], 1);
|
||||||
|
QCOMPARE(c->functionCount[SetGeometry], 1);
|
||||||
|
QCOMPARE(d->functionCount[SetGeometry], 1);
|
||||||
|
// Since nothing really changed, blay and dlay don't need
|
||||||
|
// to be resized.
|
||||||
|
QCOMPARE(blay->functionCount[SetGeometry], 0);
|
||||||
|
QCOMPARE(clay->functionCount[SetGeometry], 1);
|
||||||
|
QCOMPARE(dlay->functionCount[SetGeometry], 0);
|
||||||
|
|
||||||
|
QCOMPARE(f->functionCount[SetGeometry], 1);
|
||||||
|
|
||||||
|
QCOMPARE(a->size(), QSizeF(150, 50));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
activateAndReset(a);
|
||||||
|
f->setPreferredSize(QSizeF(60,50));
|
||||||
|
QCOMPARE(alay->isActivated(), false);
|
||||||
|
QCOMPARE(blay->isActivated(), true);
|
||||||
|
QCOMPARE(clay->isActivated(), false);
|
||||||
|
QCOMPARE(dlay->isActivated(), true);
|
||||||
|
|
||||||
|
QCOMPARE(c->eventCount(QEvent::LayoutRequest), 0);
|
||||||
|
QCoreApplication::sendPostedEvents();
|
||||||
|
QCOMPARE(a->eventCount(QEvent::LayoutRequest), 1);
|
||||||
|
QCOMPARE(b->eventCount(QEvent::LayoutRequest), 0);
|
||||||
|
QCOMPARE(c->eventCount(QEvent::LayoutRequest), 1);
|
||||||
|
QCOMPARE(d->eventCount(QEvent::LayoutRequest), 0);
|
||||||
|
|
||||||
|
QCOMPARE(a->functionCount[SetGeometry], 1);
|
||||||
|
QCOMPARE(alay->functionCount[SetGeometry], 1);
|
||||||
|
|
||||||
|
QCOMPARE(b->functionCount[SetGeometry], 1);
|
||||||
|
QCOMPARE(c->functionCount[SetGeometry], 1);
|
||||||
|
QCOMPARE(d->functionCount[SetGeometry], 1);
|
||||||
|
// f actually got wider, need to rearrange its siblings
|
||||||
|
QCOMPARE(blay->functionCount[SetGeometry], 1);
|
||||||
|
QCOMPARE(clay->functionCount[SetGeometry], 1);
|
||||||
|
QCOMPARE(dlay->functionCount[SetGeometry], 1);
|
||||||
|
|
||||||
|
QCOMPARE(e->functionCount[SetGeometry], 1);
|
||||||
|
QCOMPARE(f->functionCount[SetGeometry], 1);
|
||||||
|
QCOMPARE(g->functionCount[SetGeometry], 1);
|
||||||
|
|
||||||
|
QVERIFY(e->size().width() < f->size().width());
|
||||||
|
QVERIFY(g->size().width() < f->size().width());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// resize f so much that it'll force a resize of the top widget
|
||||||
|
// this will currently generate two setGeometry() calls on the child layout
|
||||||
|
// of the top widget.
|
||||||
|
activateAndReset(a);
|
||||||
|
f->setPreferredSize(QSizeF());
|
||||||
|
f->setMinimumSize(QSizeF(200,50));
|
||||||
|
QCOMPARE(alay->isActivated(), false);
|
||||||
|
QCOMPARE(blay->isActivated(), true);
|
||||||
|
QCOMPARE(clay->isActivated(), false);
|
||||||
|
QCOMPARE(dlay->isActivated(), true);
|
||||||
|
|
||||||
|
QCOMPARE(c->eventCount(QEvent::LayoutRequest), 0);
|
||||||
|
QCoreApplication::sendPostedEvents();
|
||||||
|
QCOMPARE(a->eventCount(QEvent::LayoutRequest), 1);
|
||||||
|
QCOMPARE(b->eventCount(QEvent::LayoutRequest), 0);
|
||||||
|
QCOMPARE(c->eventCount(QEvent::LayoutRequest), 1);
|
||||||
|
QCOMPARE(d->eventCount(QEvent::LayoutRequest), 0);
|
||||||
|
|
||||||
|
QCOMPARE(a->functionCount[SetGeometry], 1);
|
||||||
|
|
||||||
|
/* well, ideally one call to setGeometry(), but it will currently
|
||||||
|
* get two calls to setGeometry():
|
||||||
|
* 1. The first LayoutRequest will call activate() - that will call
|
||||||
|
* setGeometry() on the layout. This geometry will be based on
|
||||||
|
* the widget geometry which is not correct at this moment.
|
||||||
|
* (it is still 150 wide)
|
||||||
|
* 2. Next, we check if the widget is top level, and then we call
|
||||||
|
* parentWidget->resize(parentWidget->size());
|
||||||
|
* This will be adjusted to be minimum 200 pixels wide.
|
||||||
|
* The new size will then be propagated down to the layout
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
QCOMPARE(alay->functionCount[SetGeometry], 2);
|
||||||
|
|
||||||
|
QCOMPARE(b->functionCount[SetGeometry], 2);
|
||||||
|
QCOMPARE(c->functionCount[SetGeometry], 2);
|
||||||
|
QCOMPARE(d->functionCount[SetGeometry], 2);
|
||||||
|
// f actually got wider, need to rearrange its siblings
|
||||||
|
QCOMPARE(blay->functionCount[SetGeometry], 1);
|
||||||
|
QCOMPARE(clay->functionCount[SetGeometry], 1);
|
||||||
|
QCOMPARE(dlay->functionCount[SetGeometry], 1);
|
||||||
|
|
||||||
|
QCOMPARE(e->functionCount[SetGeometry], 1);
|
||||||
|
QCOMPARE(f->functionCount[SetGeometry], 1);
|
||||||
|
QCOMPARE(g->functionCount[SetGeometry], 1);
|
||||||
|
|
||||||
|
QVERIFY(e->size().width() < f->size().width());
|
||||||
|
QVERIFY(g->size().width() < f->size().width());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
f->setPreferredSize(QSizeF());
|
||||||
|
f->setMinimumSize(QSizeF());
|
||||||
|
a->adjustSize();
|
||||||
|
activateAndReset(a);
|
||||||
|
// update two different leaf widgets,
|
||||||
|
// eventCount and functionCount should never be >= 2
|
||||||
|
e->callUpdateGeometry();
|
||||||
|
g->callUpdateGeometry();
|
||||||
|
QCOMPARE(alay->isActivated(), false);
|
||||||
|
QCOMPARE(blay->isActivated(), false);
|
||||||
|
QCOMPARE(clay->isActivated(), true);
|
||||||
|
QCOMPARE(dlay->isActivated(), false);
|
||||||
|
|
||||||
|
QCoreApplication::sendPostedEvents();
|
||||||
|
QCOMPARE(a->eventCount(QEvent::LayoutRequest), 1);
|
||||||
|
QCOMPARE(b->eventCount(QEvent::LayoutRequest), 1);
|
||||||
|
QCOMPARE(c->eventCount(QEvent::LayoutRequest), 0);
|
||||||
|
QCOMPARE(d->eventCount(QEvent::LayoutRequest), 1);
|
||||||
|
|
||||||
|
QCOMPARE(a->functionCount[SetGeometry], 1);
|
||||||
|
QCOMPARE(alay->functionCount[SetGeometry], 1);
|
||||||
|
|
||||||
|
QCOMPARE(b->functionCount[SetGeometry], 1);
|
||||||
|
QCOMPARE(c->functionCount[SetGeometry], 1);
|
||||||
|
QCOMPARE(d->functionCount[SetGeometry], 1);
|
||||||
|
// f actually got wider, need to rearrange its siblings
|
||||||
|
QCOMPARE(blay->functionCount[SetGeometry], 1);
|
||||||
|
QCOMPARE(clay->functionCount[SetGeometry], 0);
|
||||||
|
QCOMPARE(dlay->functionCount[SetGeometry], 1);
|
||||||
|
|
||||||
|
QCOMPARE(e->functionCount[SetGeometry], 1);
|
||||||
|
QCOMPARE(f->functionCount[SetGeometry], 0);
|
||||||
|
QCOMPARE(g->functionCount[SetGeometry], 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QGraphicsLayout::setInstantInvalidatePropagation(false);
|
||||||
|
}
|
||||||
|
|
||||||
class Layout : public QGraphicsLayout
|
class Layout : public QGraphicsLayout
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -94,6 +94,7 @@ private slots:
|
|||||||
void itemSpacing();
|
void itemSpacing();
|
||||||
void setStretchFactor_data();
|
void setStretchFactor_data();
|
||||||
void setStretchFactor();
|
void setStretchFactor();
|
||||||
|
void testStretch();
|
||||||
void defaultStretchFactors_data();
|
void defaultStretchFactors_data();
|
||||||
void defaultStretchFactors();
|
void defaultStretchFactors();
|
||||||
void sizeHint_data();
|
void sizeHint_data();
|
||||||
@ -667,6 +668,10 @@ void tst_QGraphicsLinearLayout::invalidate()
|
|||||||
layout.setContentsMargins(0, 0, 0, 0);
|
layout.setContentsMargins(0, 0, 0, 0);
|
||||||
view.show();
|
view.show();
|
||||||
widget->show();
|
widget->show();
|
||||||
|
//QTest::qWait(1000);
|
||||||
|
QTest::qWaitForWindowShown(&view);
|
||||||
|
qApp->processEvents();
|
||||||
|
layout.layoutRequest = 0;
|
||||||
|
|
||||||
layout.setContentsMargins(1, 2, 3, 4);
|
layout.setContentsMargins(1, 2, 3, 4);
|
||||||
QApplication::sendPostedEvents(0, 0);
|
QApplication::sendPostedEvents(0, 0);
|
||||||
@ -1130,6 +1135,41 @@ void tst_QGraphicsLinearLayout::setStretchFactor()
|
|||||||
delete widget;
|
delete widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QGraphicsLinearLayout::testStretch()
|
||||||
|
{
|
||||||
|
QGraphicsScene scene;
|
||||||
|
QGraphicsView *view = new QGraphicsView(&scene);
|
||||||
|
QGraphicsWidget *form = new QGraphicsWidget(0, Qt::Window);
|
||||||
|
|
||||||
|
scene.addItem(form);
|
||||||
|
form->setMinimumSize(600, 600);
|
||||||
|
form->setMaximumSize(600, 600);
|
||||||
|
QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(Qt::Horizontal, form);
|
||||||
|
QGraphicsWidget *w1 = new RectWidget;
|
||||||
|
w1->setPreferredSize(100,100);
|
||||||
|
w1->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||||
|
QGraphicsWidget *w2 = new RectWidget;
|
||||||
|
w2->setPreferredSize(200,200);
|
||||||
|
w2->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||||
|
layout->setSpacing(0);
|
||||||
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
layout->addItem(w1);
|
||||||
|
layout->addStretch(2);
|
||||||
|
layout->addItem(w2);
|
||||||
|
QCOMPARE(layout->count(), 2);
|
||||||
|
QVERIFY(layout->itemAt(0) == w1);
|
||||||
|
QVERIFY(layout->itemAt(1) == w2);
|
||||||
|
layout->activate();
|
||||||
|
|
||||||
|
//view->setSceneRect(-50, -50, 800, 800);
|
||||||
|
//view->show();
|
||||||
|
//QTest::qWaitForWindowShown(view);
|
||||||
|
//QTest::qWait(5000);
|
||||||
|
QCOMPARE(form->geometry().size(), QSizeF(600,600));
|
||||||
|
QCOMPARE(w1->geometry(), QRectF(0, 0, 100, 100));
|
||||||
|
QCOMPARE(w2->geometry(), QRectF(400, 0, 200, 200));
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QGraphicsLinearLayout::defaultStretchFactors_data()
|
void tst_QGraphicsLinearLayout::defaultStretchFactors_data()
|
||||||
{
|
{
|
||||||
QTest::addColumn<Qt::Orientation>("orientation");
|
QTest::addColumn<Qt::Orientation>("orientation");
|
||||||
|
@ -186,7 +186,6 @@ private slots:
|
|||||||
void task250119_shortcutContext();
|
void task250119_shortcutContext();
|
||||||
void QT_BUG_6544_tabFocusFirstUnsetWhenRemovingItems();
|
void QT_BUG_6544_tabFocusFirstUnsetWhenRemovingItems();
|
||||||
void QT_BUG_12056_tabFocusFirstUnsetWhenRemovingItems();
|
void QT_BUG_12056_tabFocusFirstUnsetWhenRemovingItems();
|
||||||
void QT_BUG_13865_doublePaintWhenAddingASubItem();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -3367,46 +3366,6 @@ void tst_QGraphicsWidget::QT_BUG_12056_tabFocusFirstUnsetWhenRemovingItems()
|
|||||||
//This should not crash
|
//This should not crash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct GreenWidget : public QGraphicsWidget
|
|
||||||
{
|
|
||||||
GreenWidget() : count(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void paint ( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * )
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
painter->setPen(Qt::green);
|
|
||||||
painter->drawRect(option->rect.adjusted(0,0,-1,-1));
|
|
||||||
}
|
|
||||||
|
|
||||||
int count;
|
|
||||||
};
|
|
||||||
|
|
||||||
void tst_QGraphicsWidget::QT_BUG_13865_doublePaintWhenAddingASubItem()
|
|
||||||
{
|
|
||||||
QGraphicsScene scene;
|
|
||||||
QGraphicsView view(&scene);
|
|
||||||
QGraphicsWidget *widget = new QGraphicsWidget;
|
|
||||||
widget->resize(100, 100);
|
|
||||||
scene.addItem(widget);
|
|
||||||
QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(widget);
|
|
||||||
|
|
||||||
view.show();
|
|
||||||
QTest::qWaitForWindowShown(&view);
|
|
||||||
QApplication::processEvents();
|
|
||||||
|
|
||||||
|
|
||||||
GreenWidget *sub = new GreenWidget;
|
|
||||||
layout->addItem(sub);
|
|
||||||
|
|
||||||
QTest::qWait(100);
|
|
||||||
QCOMPARE(sub->count, 1); //it should only be painted once
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
QTEST_MAIN(tst_QGraphicsWidget)
|
QTEST_MAIN(tst_QGraphicsWidget)
|
||||||
#include "tst_qgraphicswidget.moc"
|
#include "tst_qgraphicswidget.moc"
|
||||||
|
|
||||||
|
@ -1,13 +1,18 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2011 Klarälvdalens Datakonsult AB,
|
** Copyright (C) 2011 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly <stephen.kelly@kdab.com>
|
||||||
** a KDAB Group company, info@kdab.com,
|
|
||||||
** author Stephen Kelly <stephen.kelly@kdab.com>
|
|
||||||
** All rights reserved.
|
** All rights reserved.
|
||||||
** Contact: Nokia Corporation (info@qt.nokia.com)
|
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||||
**
|
**
|
||||||
** This file is part of the QtGui module of the Qt Toolkit.
|
** This file is part of the QtGui module of the Qt Toolkit.
|
||||||
**
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:LGPL$
|
||||||
|
** No Commercial Usage
|
||||||
|
** This file contains pre-release code and may not be distributed.
|
||||||
|
** You may use this file in accordance with the terms and conditions
|
||||||
|
** contained in the Technology Preview License Agreement accompanying
|
||||||
|
** this package.
|
||||||
|
**
|
||||||
** GNU Lesser General Public License Usage
|
** GNU Lesser General Public License Usage
|
||||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||||
** General Public License version 2.1 as published by the Free Software
|
** General Public License version 2.1 as published by the Free Software
|
||||||
@ -20,17 +25,17 @@
|
|||||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||||
**
|
**
|
||||||
** GNU General Public License Usage
|
** If you have questions regarding the use of this file, please contact
|
||||||
** Alternatively, this file may be used under the terms of the GNU General
|
** Nokia at qt-info@nokia.com.
|
||||||
** Public License version 3.0 as published by the Free Software Foundation
|
|
||||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
|
||||||
** file. Please review the following information to ensure the GNU General
|
|
||||||
** Public License version 3.0 requirements will be met:
|
|
||||||
** http://www.gnu.org/copyleft/gpl.html.
|
|
||||||
**
|
**
|
||||||
** Other Usage
|
**
|
||||||
** Alternatively, this file may be used in accordance with the terms and
|
**
|
||||||
** conditions contained in a signed written agreement between you and Nokia.
|
**
|
||||||
|
**
|
||||||
|
**
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
3
tests/auto/qmake/testdata/subdir_via_pro_file_extra_target/simple/main.cpp
vendored
Normal file
3
tests/auto/qmake/testdata/subdir_via_pro_file_extra_target/simple/main.cpp
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
int main(int,char**)
|
||||||
|
{
|
||||||
|
}
|
5
tests/auto/qmake/testdata/subdir_via_pro_file_extra_target/simple/simple.pro
vendored
Normal file
5
tests/auto/qmake/testdata/subdir_via_pro_file_extra_target/simple/simple.pro
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
TEMPLATE = app
|
||||||
|
SOURCES = main.cpp
|
||||||
|
|
||||||
|
extratarget.commands = @echo extra target worked OK
|
||||||
|
QMAKE_EXTRA_TARGETS += extratarget
|
7
tests/auto/qmake/testdata/subdir_via_pro_file_extra_target/subdir.pro
vendored
Normal file
7
tests/auto/qmake/testdata/subdir_via_pro_file_extra_target/subdir.pro
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
TEMPLATE = subdirs
|
||||||
|
SUBDIRS = simple
|
||||||
|
|
||||||
|
extratarget.CONFIG = recursive
|
||||||
|
extratarget.recurse = $$SUBDIRS
|
||||||
|
extratarget.recurse_target = extratarget
|
||||||
|
QMAKE_EXTRA_TARGETS += extratarget
|
@ -0,0 +1,7 @@
|
|||||||
|
TEMPLATE = subdirs
|
||||||
|
SUBDIRS = subdir.pro
|
||||||
|
|
||||||
|
extratarget.CONFIG = recursive
|
||||||
|
extratarget.recurse = $$SUBDIRS
|
||||||
|
extratarget.recurse_target = extratarget
|
||||||
|
QMAKE_EXTRA_TARGETS += extratarget
|
@ -69,6 +69,7 @@ private slots:
|
|||||||
void simple_lib();
|
void simple_lib();
|
||||||
void simple_dll();
|
void simple_dll();
|
||||||
void subdirs();
|
void subdirs();
|
||||||
|
void subdir_via_pro_file_extra_target();
|
||||||
void functions();
|
void functions();
|
||||||
void operators();
|
void operators();
|
||||||
void variables();
|
void variables();
|
||||||
@ -234,6 +235,19 @@ void tst_qmake::subdirs()
|
|||||||
QVERIFY( test_compiler.removeMakefile( workDir ) );
|
QVERIFY( test_compiler.removeMakefile( workDir ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_qmake::subdir_via_pro_file_extra_target()
|
||||||
|
{
|
||||||
|
QString workDir = base_path + "/testdata/subdir_via_pro_file_extra_target";
|
||||||
|
|
||||||
|
QDir D;
|
||||||
|
D.remove( workDir + "/Makefile");
|
||||||
|
D.remove( workDir + "/Makefile.subdir");
|
||||||
|
D.remove( workDir + "/simple/Makefile");
|
||||||
|
D.remove( workDir + "/simple/Makefile.subdir");
|
||||||
|
QVERIFY( test_compiler.qmake( workDir, "subdir_via_pro_file_extra_target" ));
|
||||||
|
QVERIFY( test_compiler.make( workDir, "extratarget" ));
|
||||||
|
}
|
||||||
|
|
||||||
void tst_qmake::functions()
|
void tst_qmake::functions()
|
||||||
{
|
{
|
||||||
QString workDir = base_path + "/testdata/functions";
|
QString workDir = base_path + "/testdata/functions";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user