Fix handling of click/hover events and add methods to allow callers to

make the icon appear clicked. Getting it in now so that it doesn't
block other work. I believe all discussed issues have been fixed with
this patch, but I'll stay around to fix any issues that remain. ;)

svn path=/trunk/KDE/kdebase/workspace/libs/plasma/; revision=749016
This commit is contained in:
Jason Stubbs 2007-12-16 10:09:07 +00:00
parent 419f8db838
commit 4fb7cbc2d6
3 changed files with 119 additions and 65 deletions

View File

@ -56,7 +56,7 @@ Icon::Private::Private()
: svg("widgets/iconbutton"),
svgElements(0),
iconSize(48, 48),
state(Private::NoState),
states(Private::NoState),
orientation(Qt::Vertical),
alignment(Qt::AlignHCenter | Qt::AlignTop),
calculateSizeRequested(true) // First time always true
@ -452,7 +452,7 @@ void Icon::calculateSize(const QStyleOptionGraphicsItem *option)
update();
}
void Icon::Private::drawBackground(QPainter *painter)
void Icon::Private::drawBackground(QPainter *painter, IconState state)
{
QString element;
if (svgElements & Private::SvgBackground) {
@ -460,8 +460,6 @@ void Icon::Private::drawBackground(QPainter *painter)
}
switch (state) {
case Private::NoState:
break;
case Private::HoverState:
if (svgElements & Private::SvgBackgroundHover) {
element = "background-hover";
@ -474,6 +472,8 @@ void Icon::Private::drawBackground(QPainter *painter)
element = "background-hover";
}
break;
default:
break;
}
if (!element.isEmpty()) {
@ -481,7 +481,7 @@ void Icon::Private::drawBackground(QPainter *painter)
}
}
void Icon::Private::drawForeground(QPainter *painter)
void Icon::Private::drawForeground(QPainter *painter, IconState state)
{
QString element;
if (svgElements & Private::SvgForeground) {
@ -489,8 +489,6 @@ void Icon::Private::drawForeground(QPainter *painter)
}
switch (state) {
case Private::NoState:
break;
case Private::HoverState:
if (svgElements & Private::SvgForegroundHover) {
element = "foreground-hover";
@ -503,6 +501,8 @@ void Icon::Private::drawForeground(QPainter *painter)
element = "foreground-hover";
}
break;
default:
break;
}
if (!element.isEmpty()) {
@ -510,7 +510,7 @@ void Icon::Private::drawForeground(QPainter *painter)
}
}
QPixmap Icon::Private::decoration(const QStyleOptionGraphicsItem *option) const
QPixmap Icon::Private::decoration(const QStyleOptionGraphicsItem *option, bool useHoverEffect) const
{
QPixmap result;
@ -519,19 +519,15 @@ QPixmap Icon::Private::decoration(const QStyleOptionGraphicsItem *option) const
const QSize size = icon.actualSize(iconSize.toSize(), mode, state);
result = icon.pixmap(size, mode, state);
if (!result.isNull())
if (!result.isNull() && useHoverEffect)
{
// Apply the configured hover effect NOTE: This has no visible effect because we
// do drawForeground() -MB
if (option->state & QStyle::State_MouseOver) {
KIconEffect *effect = KIconLoader::global()->iconEffect();
KIconEffect *effect = KIconLoader::global()->iconEffect();
// Note that in KIconLoader terminology, active = hover.
// ### We're assuming that the icon group is desktop/filemanager, since this
// is KFileItemDelegate.
if (effect->hasEffect(KIconLoader::Desktop, KIconLoader::ActiveState)) {
result = effect->apply(result, KIconLoader::Desktop, KIconLoader::ActiveState);
}
// Note that in KIconLoader terminology, active = hover.
// ### We're assuming that the icon group is desktop/filemanager, since this
// is KFileItemDelegate.
if (effect->hasEffect(KIconLoader::Desktop, KIconLoader::ActiveState)) {
result = effect->apply(result, KIconLoader::Desktop, KIconLoader::ActiveState);
}
}
@ -791,7 +787,18 @@ void Icon::paintWidget(QPainter *painter, const QStyleOptionGraphicsItem *option
// Compute the metrics, and lay out the text items
// ========================================================================
QPixmap icon = d->decoration(option);
Private::IconState state = Private::NoState;
if (d->states & Private::ManualPressedState) {
state = Private::PressedState;
} else if (d->states & Private::PressedState) {
if (d->states & Private::HoverState) {
state = Private::PressedState;
}
} else if (d->states & Private::HoverState) {
state = Private::HoverState;
}
QPixmap icon = d->decoration(option, state != Private::NoState);
const QPointF iconPos = d->iconPosition(option, icon);
QTextLayout labelLayout, infoLayout;
@ -799,12 +806,12 @@ void Icon::paintWidget(QPainter *painter, const QStyleOptionGraphicsItem *option
d->layoutTextItems(option, icon, &labelLayout, &infoLayout, &textBoundingRect);
d->svg.resize(size());
d->drawBackground(painter);
d->drawBackground(painter, state);
// draw icon
painter->drawPixmap(iconPos, icon);
d->drawForeground(painter);
d->drawForeground(painter, state);
// Draw corner actions
foreach (IconAction *action, d->cornerActions) {
@ -905,7 +912,7 @@ void Icon::setIconSize(int w, int h)
bool Icon::isDown()
{
return d->state == Private::PressedState;
return d->states & Private::PressedState;
}
void Icon::mousePressEvent(QGraphicsSceneMouseEvent *event)
@ -915,47 +922,67 @@ void Icon::mousePressEvent(QGraphicsSceneMouseEvent *event)
return;
}
//kDebug();
d->states |= Private::PressedState;
bool handled = false;
foreach (IconAction *action, d->cornerActions) {
action->event(event->type(), event->pos());
handled = action->event(event->type(), event->pos());
if (handled) {
break;
}
}
d->state = Private::PressedState;
emit pressed(true);
if (!handled) {
emit pressed(true);
}
event->accept();
update();
}
void Icon::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
if (~d->states & Private::PressedState) {
Widget::mouseMoveEvent(event);
return;
}
if (boundingRect().contains(event->pos())) {
if (~d->states & Private::HoverState) {
d->states |= Private::HoverState;
update();
}
} else {
if (d->states & Private::HoverState) {
d->states &= ~Private::HoverState;
update();
}
}
}
void Icon::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
//kDebug();
bool inside = boundingRect().contains(event->pos());
Private::ButtonState was = d->state;
if (inside) {
d->state = Private::HoverState;
foreach (IconAction *action, d->cornerActions) {
if (action->event(event->type(), event->pos())) {
inside = false;
break;
}
}
} else {
d->state = Private::NoState;
if (~d->states & Private::PressedState) {
Widget::mouseMoveEvent(event);
return;
}
if (was == Private::PressedState) {
emit pressed(false);
d->states &= ~Private::PressedState;
if (inside) {
bool handled = false;
foreach (IconAction *action, d->cornerActions) {
if (action->event(event->type(), event->pos())) {
handled = true;
break;
}
}
if (!handled) {
if (boundingRect().contains(event->pos())) {
emit clicked();
}
d->state = Private::NoState;
emit pressed(false);
}
event->ignore();
update();
}
@ -966,7 +993,9 @@ void Icon::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
action->event(event->type(), event->pos());
}
d->state = Private::HoverState;
d->states |= Private::HoverState;
update();
Widget::hoverEnterEvent(event);
}
@ -977,17 +1006,25 @@ void Icon::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
action->event(event->type(), event->pos());
}
d->state = Private::NoState;
d->states &= ~Private::HoverState;
update();
Widget::hoverLeaveEvent(event);
}
void Icon::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
void Icon::setPressed(bool pressed)
{
if (d->state == Private::PressedState) {
d->state = Private::HoverState;
if (pressed) {
d->states |= Private::ManualPressedState;
} else {
d->states &= ~Private::ManualPressedState;
}
update();
}
Widget::mouseMoveEvent(event);
void Icon::setUnpressed()
{
setPressed(false);
}
void Icon::setAlignment(Qt::Alignment alignment)

View File

@ -155,6 +155,19 @@ public:
Qt::Orientations expandingDirections() const;
public slots:
/**
* Sets the appearance of the icon to pressed or restores the appearance
* to normal. This does not simulate a mouse button press.
* @param pressed whether to appear as pressed (true) or as normal (false)
*/
void setPressed(bool pressed=true);
/**
* Shortcut for setPressed(false)
*/
void setUnpressed();
protected:
void paintWidget(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);

View File

@ -92,17 +92,26 @@ class Icon::Private
public:
enum MarginType { ItemMargin = 0, TextMargin, IconMargin, NMargins };
enum IconState
{
NoState = 0,
HoverState = 1,
PressedState = 2,
ManualPressedState = 4
};
Q_DECLARE_FLAGS(IconStates, IconState);
public:
Private();
~Private();
void drawBackground(QPainter *painter);
void drawForeground(QPainter *painter);
void drawBackground(QPainter *painter, IconState state);
void drawForeground(QPainter *painter, IconState state);
void drawText(QPainter *painter);
void drawTextItems(QPainter *painter, const QStyleOptionGraphicsItem *option,
const QTextLayout &labelLayout, const QTextLayout &infoLayout) const;
QPixmap decoration(const QStyleOptionGraphicsItem *option) const;
QPixmap decoration(const QStyleOptionGraphicsItem *option, bool useHoverEffect) const;
QPointF iconPosition(const QStyleOptionGraphicsItem *option, const QPixmap &pixmap) const;
QSizeF displaySizeHint(const QStyleOptionGraphicsItem *option) const;
@ -158,13 +167,6 @@ public:
LastIconPosition
};
enum ButtonState
{
NoState,
HoverState,
PressedState
};
QString text;
QString infoText;
Svg svg;
@ -172,7 +174,7 @@ public:
QSizeF size;
QSizeF iconSize;
QIcon icon;
ButtonState state;
IconStates states;
Qt::Orientation orientation;
Qt::Alignment alignment;
bool calculateSizeRequested;
@ -184,6 +186,8 @@ public:
Margin *activeMargins;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(Icon::Private::IconStates);
// Inline methods
void Icon::Private::setLayoutOptions(QTextLayout &layout, const QStyleOptionGraphicsItem *option) const
{