[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-core-devel
Subject: Re: RFC: KToolBox
From: "Matt Broadstone" <mbroadst () gmail ! com>
Date: 2006-09-02 21:06:24
Message-ID: 621909c70609021406p6f5d9a40yc923f1dd48756aea () mail ! gmail ! com
[Download RAW message or body]
Right - would probably help if I actually attached the class :)
On 9/2/06, Matt Broadstone <mbroadst@gmail.com> wrote:
> Attached is a replacement for the QToolBox that I have written. It's
> mainly intended to look MUCH better than the old tool box, but it has
> a few differences. Notably, there is no longer a concept of a "current
> page," as we had in QToolBox, also there is no longer a QScrollArea
> for each individual page in the toolbox, but instead one large one for
> the whole box. Lastly, you can choose a title and icon for the
> toolbox. Beyond that (sorry if I've forgotten anything) it tries to
> maintain as much of the api of the original QToolBox as possible so as
> to be somewhat of a drop-in replacement for it (not like ANYONE uses
> the QToolBox in kdelibs and kdebase, hopefully because it was too ugly
> :) ). Anyway - hope you all dig it, please let me know what you think
> can be improved, and hopefully we can get this in kdeui sooner than
> later.
>
> Matt Broadstone
>
["ktoolbox.h" (text/x-chdr)]
/*
This file is part of the KDE libraries
Copyright (C) 2006 Matt Broadstone <mbroadst@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KTOOLBOX_H
#define KTOOLBOX_H
#include <QFrame>
class KToolBox : public QFrame
{
Q_OBJECT
public:
KToolBox(QWidget *parent = 0);
KToolBox(const QString &title, QWidget *parent = 0);
KToolBox(const QString &title, const QIcon &icon, QWidget *parent = 0);
~KToolBox();
int addItem(QWidget *widget, const QString &text);
int addItem(QWidget *widget, const QIcon &icon, const QString &text);
int insertItem(int index, QWidget *widget, const QString &text);
int insertItem(int index, QWidget *widget, const QIcon &icon, const QString &text);
void removeItem(int index);
void setTitle(const QString &text);
QString title() const;
void setIcon(const QIcon &icon);
QIcon icon() const;
void setItemEnabled(int index, bool enabled);
bool isItemEnabled(int index) const;
void setItemIcon(int index, const QIcon &icon);
QIcon itemIcon(int index) const;
void setItemText(int index, const QString &text);
QString itemText(int index) const;
void setItemToolTip(int index, const QString &toolTip);
QString itemToolTip(int index) const;
QWidget *widget(int index) const;
int indexOf(QWidget *widget) const;
int count() const;
signals:
void currentChanged(int index);
void itemInserted(int index);
void itemRemoved(int index);
protected:
void showEvent(QShowEvent *e);
void changeEvent(QEvent *);
private slots:
void tabSelected();
void widgetDestroyed(QObject*);
private:
class Private;
Private *d;
};
#endif
["ktoolbox.cpp" (text/x-c++src)]
/*
This file is part of the KDE libraries
Copyright (C) 2006 Matt Broadstone <mbroadst@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <QScrollArea>
#include <QVBoxLayout>
#include <QPainter>
#include <QPaintEvent>
#include <QPainterPath>
#include <QPen>
#include <QStyle>
#include <QStyleOptionToolBox>
#include <QApplication>
#include <QToolButton>
#include <QMenu>
#include <QDebug>
#include "ktoolbox.h"
#include "moc_ktoolbox.cpp"
class KToolBoxHeader : public QFrame
{
public:
KToolBoxHeader(QWidget *parent = 0);
QIcon icon() const { return m_icon; }
void setIcon(const QIcon &icon) { m_icon = icon; }
QString text() const { return m_text; }
void setText(const QString &text) { m_text = text; }
QSize sizeHint() const;
QSize minimumSizeHint() const;
protected:
void paintEvent(QPaintEvent *event);
private:
QIcon m_icon;
QString m_text;
QMenu *m_menu;
QToolButton *m_viewControl;
};
class KToolBoxBase : public QFrame
{
public:
KToolBoxBase(QWidget *parent = 0);
protected:
void paintEvent(QPaintEvent *event);
};
class KToolBoxFooter : public QFrame
{
public:
KToolBoxFooter(QWidget *parent = 0);
protected:
void paintEvent(QPaintEvent *event);
};
class KToolBoxTab : public QAbstractButton
{
public:
KToolBoxTab(QWidget *parent = 0);
void setSelected(bool);
bool isSelected() const;
QSize sizeHint() const;
QSize minimumSizeHint() const;
protected:
void paintEvent(QPaintEvent *);
private:
bool selected;
};
class KToolBox::Private
{
public:
struct Item
{
QFrame *base;
QVBoxLayout *layout;
KToolBoxTab *tab;
QWidget *widget;
inline void setText(const QString &text) { tab->setText(text); }
inline void setIcon(const QIcon &icon) { tab->setIcon(icon); }
inline void setToolTip(const QString &tip) { tab->setToolTip(tip); }
inline QString text() const { return tab->text(); }
inline QIcon icon() const { return tab->icon(); }
inline QString toolTip() const { return tab->toolTip(); }
inline bool operator==(const Item& other) const
{
return widget == other.widget;
}
};
void init(const QString &title, const QIcon &icon, QFrame *parent);
QList<Item> itemList;
Item *item(QWidget *widget) const;
const Item *item(int index) const;
Item *item(int index);
void relayout();
void updateTabs();
QVBoxLayout *layout;
KToolBoxHeader *header;
KToolBoxBase *base;
KToolBoxFooter *footer;
QScrollArea *scrollArea;
QFrame *viewport;
QVBoxLayout *viewportLayout;
};
KToolBox::KToolBox(const QString &title, QWidget *parent)
: QFrame(parent)
{
d = new Private;
d->init(title, QIcon(), this);
}
KToolBox::KToolBox(const QString &title, const QIcon &icon, QWidget *parent)
: QFrame(parent)
{
d = new Private;
d->init(title, icon, this);
}
KToolBox::KToolBox(QWidget *parent)
: QFrame(parent)
{
d = new Private;
d->init(QString(), QIcon(), this);
}
void KToolBox::Private::init(const QString &title, const QIcon &icon, QFrame *parent)
{
header = new KToolBoxHeader;
header->setText(title);
header->setIcon(icon);
base = new KToolBoxBase;
footer = new KToolBoxFooter;
viewport = new QFrame;
viewport->setFrameStyle(QFrame::NoFrame);
scrollArea = new QScrollArea;
scrollArea->setWidget(viewport);
scrollArea->setWidgetResizable(true);
scrollArea->setFrameStyle(QFrame::NoFrame);
viewportLayout = new QVBoxLayout(viewport);
viewportLayout->setMargin(0);
viewportLayout->setSpacing(2);
viewportLayout->addStretch();
QVBoxLayout *baseLayout = new QVBoxLayout(base);
baseLayout->setMargin(2);
baseLayout->setSpacing(0);
baseLayout->addWidget(scrollArea);
layout = new QVBoxLayout(parent);
layout->setMargin(0);
layout->setSpacing(0);
layout->addWidget(header);
layout->addWidget(base);
layout->addWidget(footer);
parent->setBackgroundRole(QPalette::Base);
}
KToolBox::~KToolBox()
{
}
int KToolBox::addItem(QWidget *item, const QString &text)
{
return insertItem(-1, item, QIcon(), text);
}
int KToolBox::addItem(QWidget *item, const QIcon &iconSet, const QString &text)
{
return insertItem(-1, item, iconSet, text);
}
int KToolBox::insertItem(int index, QWidget *item, const QString &text)
{
return insertItem(index, item, QIcon(), text);
}
int KToolBox::insertItem(int index, QWidget *widget, const QIcon &icon, const QString \
&text) {
if (!widget)
return -1;
connect(widget, SIGNAL(destroyed(QObject*)), this, \
SLOT(widgetDestroyed(QObject*)));
Private::Item page;
page.widget = widget;
page.tab = new KToolBoxTab;
connect(page.tab, SIGNAL(clicked()), this, SLOT(tabSelected()));
page.base = new QFrame;
page.layout = new QVBoxLayout(page.base);
page.layout->addWidget(widget);
page.base->hide();
page.base->setFrameStyle(QFrame::NoFrame);
page.setText(text);
page.setIcon(icon);
if (index < 0 || index >= d->itemList.count())
{
index = d->itemList.count();
d->itemList.append(page);
/*
viewportLayout->addWidget(page.tab);
viewportLayout->addWidget(page.base);
viewportLayout->addStretch();
*/
}
else
{
d->itemList.insert(index, page);
// relayout();
}
d->relayout();
page.tab->show();
d->updateTabs();
return index;
}
void KToolBox::tabSelected()
{
KToolBoxTab *tab = qobject_cast<KToolBoxTab*>(sender());
QFrame *base = 0;
foreach (Private::Item page, d->itemList)
{
if (page.tab == tab)
{
base = page.base;
break;
}
}
if (tab->isSelected())
{
tab->setSelected(false);
base->hide();
}
else
{
tab->setSelected(true);
base->show();
}
d->updateTabs();
}
void KToolBox::widgetDestroyed(QObject *object)
{
QWidget *p = (QWidget*)object;
Private::Item *c = d->item(p);
if (!p || !c)
return;
d->viewportLayout->removeWidget(c->base);
d->viewportLayout->removeWidget(c->tab);
c->base->deleteLater();
delete c->tab;
d->itemList.removeAll(*c);
}
void KToolBox::removeItem(int index)
{
if (QWidget *w = widget(index))
{
disconnect(w, SIGNAL(destroyed(QObject*)), this, \
SLOT(widgetDestroyed(QObject*))); w->setParent(this);
widgetDestroyed(w);
}
}
QWidget *KToolBox::widget(int index) const
{
if (index < 0 || index >= (int)d->itemList.size())
return 0;
return d->itemList.at(index).widget;
}
int KToolBox::indexOf(QWidget *widget) const
{
Private::Item *c = d->item(widget);
return c ? d->itemList.indexOf(*c) : -1;
}
void KToolBox::setItemEnabled(int index, bool enabled)
{
Private::Item *c = d->item(index);
if (!c)
return;
c->tab->setEnabled(enabled);
}
void KToolBox::setTitle(const QString &text)
{
if (d->header)
d->header->setText(text);
}
void KToolBox::setIcon(const QIcon &icon)
{
if (d->header)
d->header->setIcon(icon);
}
void KToolBox::setItemText(int index, const QString &text)
{
Private::Item *c = d->item(index);
if (c)
c->setText(text);
}
void KToolBox::setItemToolTip(int index, const QString &toolTip)
{
Private::Item *c = d->item(index);
if (c)
c->setToolTip(toolTip);
}
bool KToolBox::isItemEnabled(int index) const
{
const Private::Item *c = d->item(index);
return c && c->tab->isEnabled();
}
QString KToolBox::title() const
{
return (d->header ? d->header->text() : QString());
}
QIcon KToolBox::icon() const
{
return (d->header ? d->header->icon() : QIcon());
}
QString KToolBox::itemText(int index) const
{
const Private::Item *c = d->item(index);
return (c ? c->text() : QString());
}
QString KToolBox::itemToolTip(int index) const
{
const Private::Item *c = d->item(index);
return (c ? c->toolTip() : QString());
}
void KToolBox::showEvent(QShowEvent *e)
{
QWidget::showEvent(e);
}
void KToolBox::changeEvent(QEvent *ev)
{
if(ev->type() == QEvent::StyleChange)
d->updateTabs();
QFrame::changeEvent(ev);
}
void KToolBox::Private::relayout()
{
delete viewportLayout;
viewportLayout = new QVBoxLayout(viewport);
viewportLayout->setMargin(0);
viewportLayout->setSpacing(1);
foreach (Item page, itemList)
{
viewportLayout->addWidget(page.tab);
viewportLayout->addWidget(page.base);
}
viewportLayout->addStretch();
}
void KToolBox::Private::updateTabs()
{
foreach (Item page, itemList)
{
KToolBoxTab *tB = page.tab;
QWidget *tW = page.widget;
{
QPalette p = tB->palette();
p.setColor(tB->backgroundRole(), \
tW->palette().color(tW->backgroundRole())); tB->setPalette(p);
tB->update();
}
}
}
KToolBox::Private::Item *KToolBox::Private::item(QWidget *widget) const
{
if (!widget)
return 0;
foreach (Item i, itemList)
{
if (i.widget == widget)
return &i;
}
return 0;
}
KToolBox::Private::Item *KToolBox::Private::item(int index)
{
if (index >= 0 && index < itemList.size())
return &itemList[index];
return 0;
}
const KToolBox::Private::Item *KToolBox::Private::item(int index) const
{
if (index >= 0 && index < itemList.size())
return &itemList.at(index);
return 0;
}
KToolBoxHeader::KToolBoxHeader(QWidget *parent)
: QFrame(parent)
{
setForegroundRole(QPalette::Base);
QFont f(font());
f.setPointSizeF(8.0);
setFont(f);
}
QSize KToolBoxHeader::sizeHint() const
{
QSize iconSize(8, 8);
if (!m_icon.isNull())
{
int icone = style()->pixelMetric(QStyle::PM_SmallIconSize);
iconSize += QSize(icone + 2, icone);
}
QSize textSize = fontMetrics().size(Qt::TextShowMnemonic, m_text) + QSize(0, 8);
QSize total(iconSize.width() + textSize.width(), qMax(iconSize.height(), \
textSize.height())); return total.expandedTo(QApplication::globalStrut());
}
QSize KToolBoxHeader::minimumSizeHint() const
{
if (m_icon.isNull())
return QSize();
int icone = style()->pixelMetric(QStyle::PM_SmallIconSize);
return QSize(icone + 8, icone + 8);
}
void KToolBoxHeader::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
QRegion space(0, 0, event->rect().width(), event->rect().height());
// top-left
space -= (QRegion( 0, 0, 1, 2 ) + QRegion( 1, 0, 1, 1 ));
// top-right
space -= (QRegion( event->rect().width() - 1, 0, 1, 2 ) + QRegion( \
event->rect().width() - 2, 0, 1, 1 ));
painter.save();
painter.setClipRegion(space);
painter.fillRect(0, 0, event->rect().width(), event->rect().height(), \
Qt::darkGray);
/*
QRect textRect = QRect(event->rect().height(), event->rect().height() / 2, \
event->rect().width() - event->rect().height(), event->rect().height()); \
painter.drawText(textRect, m_text);
*/
painter.restore();
QPainter *p = &painter;
const QPalette &pal = palette();
QStyleOptionToolBox opt;
opt.init(this);
// if (selected)
opt.state |= QStyle::State_Selected;
// if (isDown())
opt.state |= QStyle::State_Sunken;
opt.text = m_text;
opt.icon = m_icon;
// style()->drawControl(QStyle::CE_ToolBoxTab, &opt, p, parentWidget());
QPixmap pm = m_icon.pixmap(style()->pixelMetric(QStyle::PM_SmallIconSize), \
QIcon::Normal);
QRect cr = style()->subElementRect(QStyle::SE_ToolBoxTabContents, &opt, this);
QRect tr, ir;
int ih = 0;
if (pm.isNull()) {
tr = cr;
tr.adjust(4, 0, -8, 0);
} else {
int iw = pm.width() + 4;
ih = pm.height();
ir = QRect(cr.left() + 4, cr.top(), iw + 2, ih);
tr = QRect(ir.right(), cr.top(), cr.width() - ir.right() - 4, cr.height());
}
QFont f(p->font());
f.setBold(true);
p->setFont(f);
// QString txt = fontMetrics().elidedText(text, Qt::ElideRight, tr.width());
QString txt = m_text;
if (ih)
p->drawPixmap(ir.left(), (height() - ih) / 2, pm);
int alignment = Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic;
if (!style()->styleHint(QStyle::SH_UnderlineShortcut, 0, this))
alignment |= Qt::TextHideMnemonic;
style()->drawItemText(p, tr, alignment, pal, true, txt, foregroundRole());
}
KToolBoxBase::KToolBoxBase(QWidget *parent)
: QFrame(parent)
{}
void KToolBoxBase::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.fillRect(event->rect(), palette().base());
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(QPen(Qt::darkGray, 3, Qt::SolidLine, Qt::RoundCap, \
Qt::RoundJoin));
painter.drawLine(event->rect().topLeft(), event->rect().bottomLeft());
painter.drawLine(event->rect().topRight(), event->rect().bottomRight());
}
KToolBoxFooter::KToolBoxFooter(QWidget *parent)
: QFrame(parent)
{
setFixedHeight(15);
setBackgroundRole(QPalette::Base);
}
void KToolBoxFooter::paintEvent(QPaintEvent *event)
{
QPainterPath path;
QRect rect(event->rect());
path.moveTo(rect.left(), rect.top());
path.lineTo(rect.left(), rect.bottom() - 5.0);
path.arcTo(rect.left(), rect.bottom() - 10.0, 10.0, 10.0, 180.0, 90.0);
path.lineTo(rect.right() - 5.0, rect.bottom());
path.arcTo(rect.right() - 10.0, rect.bottom() - 10.0, 10.0, 10.0, 270.0, 90.0);
path.lineTo(rect.right(), rect.top());
QPainter painter(this);
painter.fillRect(rect, palette().base());
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(QPen(Qt::darkGray, 3, Qt::SolidLine, Qt::RoundCap, \
Qt::RoundJoin)); painter.drawPath(path);
}
KToolBoxTab::KToolBoxTab(QWidget *parent)
: QAbstractButton(parent),
selected(false)
{
setBackgroundRole(QPalette::Window);
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
setFocusPolicy(Qt::NoFocus);
QFont tmp(font());
tmp.setPointSizeF(8.0);
setFont(tmp);
}
void KToolBoxTab::setSelected(bool b)
{
selected = b;
update();
}
bool KToolBoxTab::isSelected() const
{
return (selected == true);
}
QSize KToolBoxTab::sizeHint() const
{
QSize iconSize(8, 8);
if (!icon().isNull())
{
int icone = style()->pixelMetric(QStyle::PM_SmallIconSize);
iconSize += QSize(icone + 2, icone);
}
QSize textSize = fontMetrics().size(Qt::TextShowMnemonic, text()) + QSize(0, 8);
QSize total(iconSize.width() + textSize.width(), qMax(iconSize.height(), \
textSize.height())); return total.expandedTo(QApplication::globalStrut());
}
QSize KToolBoxTab::minimumSizeHint() const
{
if (icon().isNull())
return QSize();
int icone = style()->pixelMetric(QStyle::PM_SmallIconSize);
return QSize(icone + 8, icone + 8);
}
void KToolBoxTab::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
QString text = QAbstractButton::text();
const QPalette &pal = palette();
painter.fillRect(event->rect(), Qt::lightGray);
QStyleOption opt;
opt.init(this);
opt.rect = QRect(0,( height() - sizeHint().height() )/2, sizeHint().height(), \
sizeHint().height());
if (selected)
{
QFont font(painter.font());
font.setBold(true);
painter.setFont(font);
style()->drawPrimitive(QStyle::PE_IndicatorArrowDown, &opt, &painter);
}
else
style()->drawPrimitive(QStyle::PE_IndicatorArrowRight, &opt, &painter);
QRect textRect = QRect(sizeHint().height(), (height() - sizeHint().height()) / 2, \
event->rect().width(), event->rect().height());
// QString txt = fontMetrics().elidedText(text, Qt::ElideRight, tr.width());
QString txt = text;
int alignment = Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic;
style()->drawItemText(&painter, textRect, alignment, pal, isEnabled(), txt, \
foregroundRole());
if (!txt.isEmpty() && hasFocus())
{
QStyleOptionFocusRect opt;
opt.rect = textRect;
opt.palette = pal;
opt.state = QStyle::State_None;
style()->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, &painter, this);
}
}
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic