/* * iconwidget.cpp - misc. Iconset- and Icon-aware widgets * Copyright (C) 2003 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "iconwidget.h" #include #include #ifndef WIDGET_PLUGIN # include "iconset.h" # include # include # include #else # include static const char *cancel_xpm[] = { "22 22 60 1", " c None", ". c #E84300", "+ c #E63F00", "@ c #D11E00", "# c #D11B00", "$ c #F69D50", "% c #F59A4D", "& c #E23800", "* c #EE5F1F", "= c #ED5A1D", "- c #CD1700", "; c #FECBA2", "> c #FEC69A", ", c #F39045", "' c #DE3200", ") c #FE7B3C", "! c #FE7234", "~ c #EC4C15", "{ c #CC1100", "] c #FEC091", "^ c #FEBA89", "/ c #F2873D", "( c #DA2C00", "_ c #FE692C", ": c #EB4712", "< c #CA0F00", "[ c #FEB480", "} c #FEAE78", "| c #F07D35", "1 c #D62600", "2 c #FEA870", "3 c #FEA166", "4 c #EF722D", "5 c #D32100", "6 c #FE9B5F", "7 c #FE9356", "8 c #F16C2A", "9 c #F16525", "0 c #FE8B4D", "a c #FE8445", "b c #EE4B15", "c c #FE6025", "d c #EE4310", "e c #C90E00", "f c #FE561D", "g c #FE4B16", "h c #EA2F08", "i c #C70900", "j c #FE4010", "k c #FE350B", "l c #EA1D03", "m c #C60700", "n c #FE2906", "o c #FE1A02", "p c #E90900", "q c #C50300", "r c #FE0A00", "s c #FE0000", "t c #E90000", "u c #C40000", " ", " ", " .+ @# ", " .$%& @*=- ", " .$;>,' @*)!~{ ", " +%>]^/( @*)!_:< ", " &,^[}|1 @*)!_:< ", " '/}2345@*)!_:< ", " (|36789)!_:< ", " 1470a)!_:< ", " 58a)!_b< ", " @9)!_cde ", " @*)!_cfghi ", " @*)!_bdgjklm ", " @*)!_: iconRects; #endif int w, h; mutable int fullW, fullH; public: IconsetSelectItem(QListBox *parent, IconsetSelectItem *after, const Iconset &_iconset) : IconWidgetItem(parent, after) { #ifndef WIDGET_PLUGIN iss = _iconset; setText( iss.name() ); w = margin; h = 2*margin; int count; QPtrListIterator it = iss.iterator(); for (count = 0; it.current(); ++it) { if ( count++ >= displayNumIcons ) break; // display only first displayNumIcons icons QPixmap pix = it.current()->pixmap(); iconRects[it.current()] = QRect( w, margin, pix.width(), pix.height() ); w += pix.width() + margin; h = QMAX( h, pix.height() + 2*margin ); connect (it.current(), SIGNAL(pixmapChanged(const QPixmap &)), SLOT(iconUpdated(const QPixmap &))); it.current()->activated(false); // start animation } QMap::Iterator it2; for (it2 = iconRects.begin(); it2 != iconRects.end(); it2++) { QRect r = it2.data(); it2.data() = QRect( r.x(), (h - r.height())/2, r.width(), r.height() ); } #else Q_UNUSED( _iconset ); #endif } ~IconsetSelectItem() { #ifndef WIDGET_PLUGIN QMap::Iterator it; for (it = iconRects.begin(); it != iconRects.end(); it++) it.key()->stop(); #endif } const Iconset *iconset() const { #ifndef WIDGET_PLUGIN return &iss; #else return 0; #endif } int height( const QListBox *lb ) const { fullH = lb->fontMetrics().lineSpacing() + 2 + h; return QMAX( fullH, QApplication::globalStrut().height() ); } int width( const QListBox *lb ) const { fullW = QMAX(lb->fontMetrics().width( text() ) + 6, w + 10); return QMAX( fullW, QApplication::globalStrut().width() ); } void paint(QPainter *painter) { #ifndef WIDGET_PLUGIN QFontMetrics fm = painter->fontMetrics(); painter->drawText( 3, fm.ascent() + (fm.leading()+1)/2 + 1, text() ); QMap::Iterator it; for (it = iconRects.begin(); it != iconRects.end(); it++) { Icon *icon = it.key(); QRect r = it.data(); painter->drawPixmap(QPoint(10 + r.left(), fm.lineSpacing() + 2 + r.top()), icon->pixmap()); } #else Q_UNUSED(painter); #endif } private slots: void iconUpdated(const QPixmap &) { #ifndef WIDGET_PLUGIN IconsetSelect *issel = (IconsetSelect *)listBox(); issel->updateItem (this); #endif } }; const int IconsetSelectItem::margin = 3; const int IconsetSelectItem::displayNumIcons = 10; class IconsetSelect::Private { public: Private() { lastItem = 0; } IconsetSelectItem *lastItem; }; IconsetSelect::IconsetSelect(QWidget *parent, const char *name) : QListBox(parent, name) { d = new Private; } IconsetSelect::~IconsetSelect() { delete d; } void IconsetSelect::insert(const Iconset &iconset) { #ifndef WIDGET_PLUGIN IconsetSelectItem *item = new IconsetSelectItem(this, d->lastItem, iconset); d->lastItem = item; #else Q_UNUSED(iconset); #endif } void IconsetSelect::moveItemUp() { if ( currentItem() < 1 ) return; IconsetSelectItem *i = (IconsetSelectItem *)item(currentItem()); if ( !i ) return; QListBoxItem *prev = i->prev()->prev(); takeItem (i); insertItem (i, prev); setSelected (i, true); setCurrentItem (i); } void IconsetSelect::moveItemDown() { if ( currentItem() == -1 || currentItem() > (int)count() - 2 ) return; IconsetSelectItem *i = (IconsetSelectItem *)item(currentItem()); if ( !i ) return; QListBoxItem *next = i->next(); takeItem (i); insertItem (i, next); setCurrentItem (i); } const Iconset *IconsetSelect::iconset() const { IconsetSelectItem *i = (IconsetSelectItem *)selectedItem(); if ( !i ) i = (IconsetSelectItem *)item(currentItem()); if ( i ) return i->iconset(); return 0; } void IconsetSelect::paintCell(QPainter *p, int row, int col) { // we'll do some caching to avoid flicker QListBoxItem *item = QListBox::item(row); if ( !item ) { QListBox::paintCell(p, row, col); return; } int w = contentsWidth(); int h = item->height(this); QPixmap pix(w, h); QPainter p2; p2.begin (&pix); QListBox::paintCell(&p2, row, col); p2.end (); p->drawPixmap(QPoint(0, 0), pix); } //---------------------------------------------------------------------------- // IconsetDisplay //---------------------------------------------------------------------------- class IconsetDisplayItem : public IconWidgetItem { Q_OBJECT private: static const int margin; Icon *icon; int w, h; public: IconsetDisplayItem(QListBox *parent, IconsetDisplayItem *after, Icon *i, int iconW) : IconWidgetItem(parent, after) { #ifndef WIDGET_PLUGIN icon = i; w = iconW; connect (icon, SIGNAL(pixmapChanged(const QPixmap &)), SLOT(iconUpdated(const QPixmap &))); icon->activated(false); h = icon->pixmap().height(); QString str; QDictIterator it ( icon->text() ); for ( ; it.current(); ++it) { if ( !str.isEmpty() ) str += ", "; str += **it; } if ( !str.isEmpty() ) setText(str); else setText(tr("Name: '%1'").arg(icon->name())); #else Q_UNUSED( i ); Q_UNUSED( iconW ); #endif } ~IconsetDisplayItem() { #ifndef WIDGET_PLUGIN icon->stop(); #endif } int height( const QListBox *lb ) const { int hh = QMAX(h + 2*margin, lb->fontMetrics().lineSpacing() + 2); return QMAX( hh, QApplication::globalStrut().height() ); } int width( const QListBox *lb ) const { int ww = lb->fontMetrics().width( text() ) + 6 + w + 2*margin; return QMAX( ww, QApplication::globalStrut().width() ); } void paint(QPainter *painter) { #ifndef WIDGET_PLUGIN painter->drawPixmap(QPoint((2*margin+w - icon->pixmap().width())/2, margin), icon->pixmap()); QFontMetrics fm = painter->fontMetrics(); //int hh = QMAX(h + 2*margin, fm.lineSpacing() + 2); painter->drawText( w + 2*margin + 3, fm.ascent() + (fm.leading()+1)/2 + 1, text() ); //painter->drawText( w + 2*margin + 3, (hh - fm.lineSpacing())/2, text() ); #else Q_UNUSED(painter); #endif } private slots: void iconUpdated(const QPixmap &) { IconsetDisplay *issel = (IconsetDisplay *)listBox(); issel->updateItem (this); } }; const int IconsetDisplayItem::margin = 3; class IconsetDisplay::Private { public: Private() { lastItem = 0; } IconsetDisplayItem *lastItem; }; IconsetDisplay::IconsetDisplay(QWidget *parent, const char *name) : QListBox(parent, name, WStaticContents | WResizeNoErase | WRepaintNoErase) { d = new Private; } IconsetDisplay::~IconsetDisplay() { delete d; } void IconsetDisplay::setIconset(const Iconset &iconset) { #ifndef WIDGET_PLUGIN int w = 0; QPtrListIterator it = iconset.iterator(); for ( ; it.current(); ++it) { w = QMAX(w, it.current()->pixmap().width()); } it = iconset.iterator(); for ( ; it.current(); ++it) { IconsetDisplayItem *item = new IconsetDisplayItem(this, d->lastItem, it.current(), w); d->lastItem = item; } #else Q_UNUSED(iconset); #endif } void IconsetDisplay::paintCell(QPainter *p, int row, int col) { // we'll do some caching to avoid flicker QListBoxItem *item = QListBox::item(row); if ( !item ) { QListBox::paintCell(p, row, col); return; } int w = contentsWidth(); int h = item->height(this); QPixmap pix(w, h); QPainter p2; p2.begin (&pix); QListBox::paintCell(&p2, row, col); p2.end (); p->drawPixmap(QPoint(0, 0), pix); } //---------------------------------------------------------------------------- // IconButton //---------------------------------------------------------------------------- class IconButton::Private : public QObject { Q_OBJECT public: Icon *icon; IconButton *button; bool textVisible; bool activate, forced; #ifdef WIDGET_PLUGIN QString iconName; #endif public: Private(IconButton *b) { icon = 0; button = b; textVisible = true; forced = false; } ~Private() { iconStop(); } void setIcon(Icon *i) { #ifndef WIDGET_PLUGIN iconStop(); if ( i ) icon = new Icon(*i); iconStart(); #else Q_UNUSED(i); #endif } void iconStart() { #ifndef WIDGET_PLUGIN if ( icon ) { connect(icon, SIGNAL(pixmapChanged(const QPixmap &)), SLOT(iconUpdated(const QPixmap &))); if ( activate ) icon->activated(true); // FIXME: should icon play sound when it's activated on button? } updateIcon(); #endif } void iconStop() { #ifndef WIDGET_PLUGIN if ( icon ) { disconnect(icon, 0, this, 0 ); if ( activate ) icon->stop(); delete icon; icon = 0; } #endif } void update() { #ifndef WIDGET_PLUGIN if ( icon ) iconUpdated( icon->pixmap() ); #endif } void updateIcon() { #ifndef WIDGET_PLUGIN if ( icon ) iconUpdated( icon->pixmap() ); else iconUpdated( QPixmap() ); #endif } public slots: void iconUpdated(const QPixmap &pix) { button->setUpdatesEnabled(FALSE); if ( textVisible || button->text().isEmpty() ) button->setIconSet(pix); else button->setPixmap(pix); button->setUpdatesEnabled(TRUE); button->update(); } }; IconButton::IconButton(QWidget *parent, const char *name) : QPushButton(parent, name) { setWFlags(getWFlags() | WRepaintNoErase); // no nasty flicker anymore :) d = new Private(this); } IconButton::~IconButton() { delete d; } void IconButton::setIcon(const QPixmap &p) { QPushButton::setIcon(p); } void IconButton::forceSetIcon(const Icon *i, bool activate) { d->activate = activate; d->setIcon ((Icon *)i); d->forced = true; } void IconButton::setIcon(const Icon *i, bool activate) { #ifndef Q_WS_X11 if ( !text().isEmpty() ) return; #endif forceSetIcon(i, activate); d->forced = false; } void IconButton::setIcon(const QString &name) { #ifndef WIDGET_PLUGIN setIcon( IconsetFactory::iconPtr(name) ); #else d->iconName = name; if ( !name.isEmpty() ) { QPixmap pix((const char **)cancel_xpm); d->iconUpdated(QPixmap( pix )); } else d->iconUpdated(QPixmap()); #endif } const QString &IconButton::iconName() const { #ifndef WIDGET_PLUGIN if ( d->icon ) return d->icon->name(); return QString::null; #else return d->iconName; #endif } void IconButton::setText(const QString &text) { #ifndef Q_WS_X11 if ( !d->forced ) setIcon(0); #endif QPushButton::setText( text ); d->updateIcon(); } bool IconButton::textVisible() const { return d->textVisible; } void IconButton::setTextVisible(bool v) { d->textVisible = v; d->updateIcon(); } void IconButton::drawButtonLabel(QPainter *p) { QPushButton::drawButtonLabel(p); } //---------------------------------------------------------------------------- // IconToolButton //---------------------------------------------------------------------------- class IconToolButton::Private : public QObject { Q_OBJECT public: Icon *icon; IconToolButton *button; bool activate; #ifdef WIDGET_PLUGIN QString iconName; #endif public: Private(IconToolButton *b) { icon = 0; button = b; } ~Private() { iconStop(); } void setIcon(Icon *i) { #ifndef WIDGET_PLUGIN iconStop(); if ( i ) icon = new Icon(*i); iconStart(); #else Q_UNUSED(i); #endif } void iconStart() { #ifndef WIDGET_PLUGIN if ( icon ) { connect(icon, SIGNAL(pixmapChanged(const QPixmap &)), SLOT(iconUpdated(const QPixmap &))); if ( activate ) icon->activated(true); // FIXME: should icon play sound when it's activated on button? iconUpdated( icon->pixmap() ); } else iconUpdated( QPixmap() ); #endif } void iconStop() { #ifndef WIDGET_PLUGIN if ( icon ) { disconnect(icon, 0, this, 0 ); if ( activate ) icon->stop(); delete icon; icon = 0; } #endif } void update() { #ifndef WIDGET_PLUGIN if ( icon ) iconUpdated( icon->pixmap() ); #endif } private slots: void iconUpdated(const QPixmap &pix) { button->setUpdatesEnabled(FALSE); //if ( textVisible ) button->setIconSet(pix); //else // button->setPixmap(pix); button->setUpdatesEnabled(TRUE); button->update(); } }; IconToolButton::IconToolButton(QWidget *parent, const char *name) : QToolButton(parent, name) { setWFlags(getWFlags() | WRepaintNoErase); d = new Private(this); } IconToolButton::~IconToolButton() { delete d; } void IconToolButton::setIcon(const QPixmap &p) { QToolButton::setIcon(p); } void IconToolButton::setIcon(const Icon *i, bool activate) { d->activate = activate; d->setIcon ((Icon *)i); } void IconToolButton::setIcon(const QString &name) { #ifndef WIDGET_PLUGIN setIcon( IconsetFactory::iconPtr(name) ); #else d->iconName = name; #endif } const QString &IconToolButton::iconName() const { #ifndef WIDGET_PLUGIN if ( d->icon ) return d->icon->name(); return QString::null; #else return d->iconName; #endif } void IconToolButton::drawButtonLabel(QPainter *p) { QToolButton::drawButtonLabel(p); } #include "iconwidget.moc"