[Ktutorial-commits] SF.net SVN: ktutorial:[240] trunk/ktutorial/ktutorial-library
Status: Alpha
Brought to you by:
danxuliu
|
From: <dan...@us...> - 2010-05-18 15:37:19
|
Revision: 240
http://ktutorial.svn.sourceforge.net/ktutorial/?rev=240&view=rev
Author: danxuliu
Date: 2010-05-18 15:37:12 +0000 (Tue, 18 May 2010)
Log Message:
-----------
Change the way widgets are highlighted: use a semi-transparent child widget over the widget to be highlighted instead of changing its palette, as some widgets like QToolButtons don't paint a background, so changing its palette had no noticeable visual effect.
Modified Paths:
--------------
trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighter.cpp
trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighter.h
trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterManagerTest.cpp
trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterTest.cpp
Modified: trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighter.cpp
===================================================================
--- trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighter.cpp 2010-05-18 15:29:49 UTC (rev 239)
+++ trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighter.cpp 2010-05-18 15:37:12 UTC (rev 240)
@@ -16,10 +16,9 @@
* along with this program; If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
-#include <QWidget>
+#include <QPainter>
+#include <QPaintEvent>
-#include <KColorUtils>
-
#include "WidgetHighlighter.h"
namespace extendedinformation {
@@ -27,12 +26,16 @@
//public:
WidgetHighlighter::WidgetHighlighter(QWidget* targetWidget):
- QObject(targetWidget),
+ QWidget(targetWidget),
mTargetWidget(targetWidget) {
Q_ASSERT(targetWidget);
- mOriginalPalette = targetWidget->palette();
+ setAttribute(Qt::WA_TransparentForMouseEvents);
+ setFocusPolicy(Qt::NoFocus);
+ resize(mTargetWidget->size());
+ mTargetWidget->installEventFilter(this);
+
//TODO Use QPropertyAnimation instead? Increase Qt version requirement in
//CMakeLists.txt to Qt 4.6 if done.
mProgress = 0;
@@ -44,11 +47,20 @@
mProgressForEachTick = interval / (qreal)duration;
mTimer.setInterval(interval);
- connect(&mTimer, SIGNAL(timeout()), this, SLOT(update()));
+ connect(&mTimer, SIGNAL(timeout()), this, SLOT(updateProgress()));
+
+ show();
}
-WidgetHighlighter::~WidgetHighlighter() {
- mTargetWidget->setPalette(mOriginalPalette);
+bool WidgetHighlighter::eventFilter(QObject* watched, QEvent* event) {
+ if (watched != mTargetWidget || event->type() != QEvent::Resize) {
+ return false;
+ }
+
+ QResizeEvent* resizeEvent = static_cast<QResizeEvent*>(event);
+ resize(resizeEvent->size());
+
+ return false;
}
//public slots:
@@ -70,35 +82,59 @@
}
}
-//private:
+//protected:
-void WidgetHighlighter::updateColorGroup(QPalette& palette,
- QPalette::ColorGroup colorGroup) {
- updateColorRole(palette, colorGroup, QPalette::Window, QPalette::Highlight);
- updateColorRole(palette, colorGroup, QPalette::WindowText,
- QPalette::HighlightedText);
- updateColorRole(palette, colorGroup, QPalette::Base, QPalette::Highlight);
- updateColorRole(palette, colorGroup, QPalette::Text,
- QPalette::HighlightedText);
- updateColorRole(palette, colorGroup, QPalette::Button, QPalette::Highlight);
- updateColorRole(palette, colorGroup, QPalette::ButtonText,
- QPalette::HighlightedText);
-}
+void WidgetHighlighter::paintEvent(QPaintEvent* event) {
+ //Painting the WidgetHighlighter over its parent widget with a
+ //semi-transpaernt color is the best I could get. However, it has some
+ //flaws. For example, a QMenu does not highlight its menu button. And some
+ //widgets may be hardly highlighted if their background color is almost the
+ //same as the highlight color (like QStatusBar in Oxygen style and default
+ //colors).
+ //
+ //Changing the parent widget palette does not work because some widgets
+ //(like tool buttons) don't paint a background, only paint the text and get
+ //its parent widget background. Forcing the painting of the background with
+ //some color role does not help, as it may look ugly in some styles that use
+ //a gradient for the background. Changing the palette has one benefit,
+ //though, as it also changes the palette from the children widgets, which
+ //means that a QMenu would highlight its menu button.
+ //
+ //Ideally, the highlighter should lighten its parent widget but when it is
+ //too bright (for example, the white background of a text edit). In that
+ //case, the parent widget should be darkened. To do this, however, the
+ //WidgetHighlighter must know how its parent widget is painted.
+ //
+ //Calling QPixmap::grabWidget from the WidgetHighlighter::paintEvent is not
+ //good, as it triggers a recursive paint event in its parent (provided the
+ //WidgetHighlighter paintEvent is guarded against a recursive call, else the
+ //application would directly hang). Calling it from the updateProgress and
+ //storing the QPixmap in memory would theoretically work, but it showed some
+ //strange artifacts.
+ //
+ //Setting a custom QGraphicsEffect does not seem like a good idea, as Qt can
+ //be compiled without them, and because, as far as I know, only one effect
+ //can be used on a widget at a time (as making a Composite design pattern
+ //with something like QComposedGraphicsEffect class is pretty easy and there
+ //is no such class, I presume that it is not a good idea to use several
+ //effects on the same widget, at least for now).
+ //
+ //Anyway, I do not know how to check whether a picture is light or dark
+ //quickly enough to be done in a realtime animation, so... a
+ //semi-transparent colored child widget is good enough until someone makes
+ //something better ;)
-void WidgetHighlighter::updateColorRole(QPalette& palette,
- QPalette::ColorGroup colorGroup,
- QPalette::ColorRole base,
- QPalette::ColorRole tint) {
- qreal amount = 0.6 * mProgress;
- QColor color = KColorUtils::tint(palette.color(colorGroup, base),
- palette.color(colorGroup, tint),
- amount);
- palette.setColor(colorGroup, base, color);
+ QColor color = mTargetWidget->palette().color(QPalette::Highlight);
+
+ QPainter painter(this);
+ painter.setOpacity(mProgress / 2.0f);
+ painter.fillRect(event->rect(), color);
+ painter.end();
}
//private slots:
-void WidgetHighlighter::update(){
+void WidgetHighlighter::updateProgress(){
if (mIncreasing) {
mProgress += mProgressForEachTick;
mProgress = qMin<qreal>(1, mProgress);
@@ -109,13 +145,8 @@
mIncreasing = mProgress == 0;
}
- QPalette updatedPalette = mOriginalPalette;
- updateColorGroup(updatedPalette, QPalette::Active);
- updateColorGroup(updatedPalette, QPalette::Inactive);
- updateColorGroup(updatedPalette, QPalette::Disabled);
+ update();
- mTargetWidget->setPalette(updatedPalette);
-
if (mStopping && mProgress == 0) {
mTimer.stop();
emit stopped(this);
Modified: trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighter.h
===================================================================
--- trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighter.h 2010-05-18 15:29:49 UTC (rev 239)
+++ trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighter.h 2010-05-18 15:37:12 UTC (rev 240)
@@ -19,32 +19,35 @@
#ifndef WIDGETHIGHLIGHTER_H
#define WIDGETHIGHLIGHTER_H
-#include <QObject>
-#include <QPalette>
#include <QTimer>
+#include <QWidget>
namespace extendedinformation {
/**
* Utility class to highlight a widget.
- * WidgetHighlighter executes an animation that modifies the color palette of
- * some widget, changing its colors from normal to highlighted and back again.
+ * WidgetHighlighter executes an animation that tints its parent widget,
+ * changing its colors from normal to highlighted and back again.
*
* Once started, the animation goes on indefinitely until the stop slot is
- * called. The colors of the palette are set back to the original colors
- * animating the change from the current color of the widget to the normal one.
+ * called. The parent widget recovers its original appearance animating the
+ * change from the current color of the widget to the normal one.
* If the highlighting is started again while the stop animation is running, the
* highlighting animation is started again from the current color (that is, the
* stop animation is cancelled and a new highlight animation is started from
* that point).
*
+ * To tint the widget, the WidgetHighlighter paints itself over the whole parent
+ * widget with a semi-transparent highlight color, so the parent widget can
+ * still be seen but tinted with the highlight color.
+ *
* WidgetHighlighter should not be created directly. Instead,
* WidgetHighlighterManager should be used, as it takes care of deleting the
* highlighter when no longer needed.
*
* @see WidgetHighlighterManager
*/
-class WidgetHighlighter: public QObject {
+class WidgetHighlighter: public QWidget {
Q_OBJECT
public:
@@ -56,10 +59,14 @@
explicit WidgetHighlighter(QWidget* targetWidget);
/**
- * Destroys this WidgetHighlighter.
- * It restores the original palette to the target widget.
+ * Resizes this WidgetHighlighter to the size of its parent widget when it
+ * receives a resize event.
+ *
+ * @param watched The filtered object that received an event.
+ * @param event The event received.
+ * @return False, to allow the event to be handled further.
*/
- virtual ~WidgetHighlighter();
+ virtual bool eventFilter(QObject* watched, QEvent* event);
public Q_SLOTS:
@@ -89,6 +96,16 @@
*/
void stopped(extendedinformation::WidgetHighlighter* widgetHighlighter);
+protected:
+
+ /**
+ * Fills the widget with a semi-transparent highlight color.
+ * The degree of opacity depends on the progress of the animation.
+ *
+ * @param event The paint event.
+ */
+ virtual void paintEvent(QPaintEvent* event);
+
private:
/**
@@ -97,11 +114,6 @@
QWidget* mTargetWidget;
/**
- * The original palette used by the widget.
- */
- QPalette mOriginalPalette;
-
- /**
* Timer to update the colors.
*/
QTimer mTimer;
@@ -127,33 +139,12 @@
*/
bool mStopping;
- /**
- * Updates the color group of the given palette based on the current
- * progress.
- *
- * @param palette The palette to update its colors.
- * @param colorGroup The color group of the palette to update.
- */
- void updateColorGroup(QPalette& palette, QPalette::ColorGroup colorGroup);
-
- /**
- * Updates the color role "base" tinting it with the color role "tint".
- * How much the base color role is tinted depends on the current progress.
- *
- * @param palette The palette to update its colors.
- * @param colorGroup The color group of the palette to update.
- * @param base The color role to update.
- * @param tint The color role to tint the base color role with.
- */
- void updateColorRole(QPalette& palette, QPalette::ColorGroup colorGroup,
- QPalette::ColorRole from, QPalette::ColorRole to);
-
private Q_SLOTS:
/**
- * Updates the palette of the target widget based on the animation progress.
+ * Updates the animation progress.
*/
- void update();
+ void updateProgress();
};
Modified: trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterManagerTest.cpp
===================================================================
--- trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterManagerTest.cpp 2010-05-18 15:29:49 UTC (rev 239)
+++ trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterManagerTest.cpp 2010-05-18 15:37:12 UTC (rev 240)
@@ -21,7 +21,11 @@
#include <QWidget>
#include "WidgetHighlighterManager.h"
+#define protected public
+#define private public
#include "WidgetHighlighter.h"
+#undef private
+#undef protected
namespace extendedinformation {
@@ -39,6 +43,10 @@
void testDeleteWidgetWhileHighlighting();
+private:
+
+ WidgetHighlighter* highlighterOf(const QWidget* widget) const;
+
};
void WidgetHighlighterManagerTest::testSelf() {
@@ -52,7 +60,6 @@
void WidgetHighlighterManagerTest::testHighlight() {
QWidget widget;
- QPalette palette = widget.palette();
WidgetHighlighterManager* manager = WidgetHighlighterManager::self();
manager->highlight(&widget);
@@ -61,8 +68,8 @@
QTest::qWait(100);
QCOMPARE(widget.findChildren<WidgetHighlighter*>().count(), 1);
- QVERIFY(widget.findChild<WidgetHighlighter*>());
- QVERIFY(widget.palette() != palette);
+ QVERIFY(highlighterOf(&widget));
+ QVERIFY(highlighterOf(&widget)->mProgress > 0);
}
void WidgetHighlighterManagerTest::testHighlightWidgetAlreadyHighlighted() {
@@ -71,12 +78,12 @@
manager->highlight(&widget);
- WidgetHighlighter* highlighter = widget.findChild<WidgetHighlighter*>();
+ WidgetHighlighter* highlighter = highlighterOf(&widget);
manager->highlight(&widget);
QCOMPARE(widget.findChildren<WidgetHighlighter*>().count(), 1);
- QCOMPARE(widget.findChild<WidgetHighlighter*>(), highlighter);
+ QCOMPARE(highlighterOf(&widget), highlighter);
}
void WidgetHighlighterManagerTest::testHighlightAfterStopHighlighting() {
@@ -85,28 +92,25 @@
manager->highlight(&widget);
- QPointer<WidgetHighlighter> highlighter =
- widget.findChild<WidgetHighlighter*>();
+ QPointer<WidgetHighlighter> highlighter = highlighterOf(&widget);
QVERIFY(highlighter);
manager->stopHighlighting(&widget);
QVERIFY(!highlighter);
- QPalette palette = widget.palette();
manager->highlight(&widget);
//Give it some time to update
QTest::qWait(100);
QCOMPARE(widget.findChildren<WidgetHighlighter*>().count(), 1);
- QVERIFY(widget.findChild<WidgetHighlighter*>());
- QVERIFY(widget.palette() != palette);
+ QVERIFY(highlighterOf(&widget));
+ QVERIFY(highlighterOf(&widget)->mProgress > 0);
}
void WidgetHighlighterManagerTest::testStopHighlighting() {
QWidget widget;
- QPalette palette = widget.palette();
WidgetHighlighterManager* manager = WidgetHighlighterManager::self();
manager->highlight(&widget);
@@ -120,7 +124,6 @@
QTest::qWait(200);
QCOMPARE(widget.findChildren<WidgetHighlighter*>().count(), 0);
- QVERIFY(widget.palette() == palette);
}
void WidgetHighlighterManagerTest::testDeleteWidgetWhileHighlighting() {
@@ -137,8 +140,20 @@
//No explicit check is made, if it does not crash everything is fine ;)
}
+WidgetHighlighter* WidgetHighlighterManagerTest::highlighterOf(
+ const QWidget* widget) const {
+ WidgetHighlighter* highlighter = widget->findChild<WidgetHighlighter*>();
+
+ //Ensure that it is a direct child
+ if (widget->children().contains(highlighter)) {
+ return highlighter;
+ }
+
+ return 0;
}
+}
+
QTEST_MAIN(extendedinformation::WidgetHighlighterManagerTest)
#include "WidgetHighlighterManagerTest.moc"
Modified: trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterTest.cpp
===================================================================
--- trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterTest.cpp 2010-05-18 15:29:49 UTC (rev 239)
+++ trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterTest.cpp 2010-05-18 15:37:12 UTC (rev 240)
@@ -39,47 +39,33 @@
void testConstructor();
- void testDestructor();
-
void testStart();
void testStartAlreadyStarted();
void testStartWhileStopAnimationIsRunning();
- void testUpdate();
- void testUpdateWhenProgressIsAlmostOne();
- void testUpdateWhenProgressIsAlmostZero();
+ void testUpdateProgress();
+ void testUpdateProgressWhenProgressIsAlmostOne();
+ void testUpdateProgressWhenProgressIsAlmostZero();
void testStop();
void testStopAfterStopAnimationEnded();
void testStopImmediatelyAfterStart();
+ void testParentWidgetResized();
+
};
void WidgetHighlighterTest::testConstructor() {
QWidget widget;
- widget.setPalette(Qt::blue);
- QApplication::setPalette(Qt::green);
WidgetHighlighter* highlighter = new WidgetHighlighter(&widget);
QCOMPARE(highlighter->parent(), &widget);
- QVERIFY(highlighter->mOriginalPalette != QApplication::palette());
- QVERIFY(highlighter->mOriginalPalette == widget.palette());
+ QCOMPARE(highlighter->size(), widget.size());
+ QCOMPARE(highlighter->mProgress, 0.0);
}
-void WidgetHighlighterTest::testDestructor() {
- QWidget widget;
- QPalette palette = widget.palette();
- WidgetHighlighter* highlighter = new WidgetHighlighter(&widget);
-
- widget.setPalette(QPalette(Qt::green));
- delete highlighter;
-
- QVERIFY(widget.palette() == palette);
-}
-
void WidgetHighlighterTest::testStart() {
QWidget widget;
- QPalette palette = widget.palette();
WidgetHighlighter* highlighter = new WidgetHighlighter(&widget);
highlighter->start();
@@ -87,12 +73,11 @@
//Give it some time to update
QTest::qWait(100);
- QVERIFY(widget.palette() != palette);
+ QVERIFY(highlighter->mProgress > 0);
}
void WidgetHighlighterTest::testStartAlreadyStarted() {
QWidget widget;
- QPalette palette = widget.palette();
WidgetHighlighter* highlighter = new WidgetHighlighter(&widget);
highlighter->start();
@@ -105,12 +90,10 @@
//Ensure that progress is not reseted
QCOMPARE(highlighter->mProgress, previousProgress);
- QVERIFY(widget.palette() != palette);
}
void WidgetHighlighterTest::testStartWhileStopAnimationIsRunning() {
QWidget widget;
- QPalette palette = widget.palette();
WidgetHighlighter* highlighter = new WidgetHighlighter(&widget);
highlighter->mProgress = 0.5;
@@ -132,82 +115,59 @@
QVERIFY(highlighter->mProgress > 0.5);
QVERIFY(highlighter->mIncreasing);
QVERIFY(!highlighter->mStopping);
- QVERIFY(widget.palette() != palette);
}
-void WidgetHighlighterTest::testUpdate() {
+void WidgetHighlighterTest::testUpdateProgress() {
QWidget widget;
WidgetHighlighter* highlighter = new WidgetHighlighter(&widget);
highlighter->mTimer.stop();
- QPalette palette = widget.palette();
int previousProgress = highlighter->mProgress;
- highlighter->update();
+ highlighter->updateProgress();
QCOMPARE(highlighter->mProgress,
previousProgress + highlighter->mProgressForEachTick);
- QVERIFY(widget.palette().color(QPalette::Window) !=
- palette.color(QPalette::Window));
- QVERIFY(widget.palette().color(QPalette::WindowText) !=
- palette.color(QPalette::WindowText));
- QVERIFY(widget.palette().color(QPalette::Base) !=
- palette.color(QPalette::Base));
- QVERIFY(widget.palette().color(QPalette::Text) !=
- palette.color(QPalette::Text));
- QVERIFY(widget.palette().color(QPalette::Button) !=
- palette.color(QPalette::Button));
- QVERIFY(widget.palette().color(QPalette::ButtonText) !=
- palette.color(QPalette::ButtonText));
}
-void WidgetHighlighterTest::testUpdateWhenProgressIsAlmostOne() {
+void WidgetHighlighterTest::testUpdateProgressWhenProgressIsAlmostOne() {
QWidget widget;
WidgetHighlighter* highlighter = new WidgetHighlighter(&widget);
highlighter->mTimer.stop();
highlighter->mProgress = 0.995;
highlighter->mIncreasing = true;
- highlighter->update();
+ highlighter->updateProgress();
- //Don't check palette changes here, as with such a small update it could
- //have been left unchanged
QCOMPARE(highlighter->mProgress, 1.0);
QCOMPARE(highlighter->mIncreasing, false);
- QPalette palette = widget.palette();
- highlighter->update();
+ highlighter->updateProgress();
QCOMPARE(highlighter->mProgress, 1 - highlighter->mProgressForEachTick);
QCOMPARE(highlighter->mIncreasing, false);
- QVERIFY(widget.palette() != palette);
}
-void WidgetHighlighterTest::testUpdateWhenProgressIsAlmostZero() {
+void WidgetHighlighterTest::testUpdateProgressWhenProgressIsAlmostZero() {
QWidget widget;
WidgetHighlighter* highlighter = new WidgetHighlighter(&widget);
highlighter->mTimer.stop();
highlighter->mProgress = 0.005;
highlighter->mIncreasing = false;
- highlighter->update();
+ highlighter->updateProgress();
- //Don't check palette changes here, as with such a small update it could
- //have been left unchanged
QCOMPARE(highlighter->mProgress, 0.0);
QCOMPARE(highlighter->mIncreasing, true);
- QPalette palette = widget.palette();
- highlighter->update();
+ highlighter->updateProgress();
QCOMPARE(highlighter->mProgress, highlighter->mProgressForEachTick);
QCOMPARE(highlighter->mIncreasing, true);
- QVERIFY(widget.palette() != palette);
}
void WidgetHighlighterTest::testStop() {
QWidget widget;
- QPalette palette = widget.palette();
WidgetHighlighter* highlighter = new WidgetHighlighter(&widget);
highlighter->mProgress = 0.5;
@@ -225,12 +185,10 @@
QVERIFY(highlighter->mProgress < 0.5);
QVERIFY(!highlighter->mIncreasing);
QVERIFY(highlighter->mStopping);
- QVERIFY(widget.palette() != palette);
}
void WidgetHighlighterTest::testStopAfterStopAnimationEnded() {
QWidget widget;
- QPalette palette = widget.palette();
WidgetHighlighter* highlighter = new WidgetHighlighter(&widget);
highlighter->start();
@@ -252,7 +210,7 @@
QTest::qWait(200);
QVERIFY(!highlighter->mTimer.isActive());
- QVERIFY(widget.palette() == palette);
+ QCOMPARE(highlighter->mProgress, 0.0);
QCOMPARE(stoppedSpy.count(), 1);
QVariant argument = stoppedSpy.at(0).at(0);
QCOMPARE(argument.userType(), widgetHighlighterStarType);
@@ -262,7 +220,6 @@
void WidgetHighlighterTest::testStopImmediatelyAfterStart() {
QWidget widget;
- QPalette palette = widget.palette();
WidgetHighlighter* highlighter = new WidgetHighlighter(&widget);
highlighter->start();
@@ -278,7 +235,7 @@
highlighter->stop();
QVERIFY(!highlighter->mTimer.isActive());
- QVERIFY(widget.palette() == palette);
+ QCOMPARE(highlighter->mProgress, 0.0);
QCOMPARE(stoppedSpy.count(), 1);
QVariant argument = stoppedSpy.at(0).at(0);
QCOMPARE(argument.userType(), widgetHighlighterStarType);
@@ -286,8 +243,23 @@
highlighter);
}
+void WidgetHighlighterTest::testParentWidgetResized() {
+ QWidget widget;
+ WidgetHighlighter* highlighter = new WidgetHighlighter(&widget);
+
+ //The widget must be visible to ensure that it receives the resize event
+ widget.show();
+
+ //Resize twice to prevent a false test if the first size was the current
+ //widget size
+ widget.resize(4, 4);
+ widget.resize(108, 108);
+
+ QCOMPARE(highlighter->size(), widget.size());
}
+}
+
QTEST_MAIN(extendedinformation::WidgetHighlighterTest)
#include "WidgetHighlighterTest.moc"
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|