mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-23 10:22:48 +00:00

there are no virtual QFrame::contentsMousePressEvent() and QTreeWidget::contentsMousePressEvent() methods Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
610 lines
16 KiB
C++
610 lines
16 KiB
C++
/***************************************************************************
|
|
kmultitabbar.cpp - description
|
|
-------------------
|
|
begin : 2001
|
|
copyright : (C) 2001,2002,2003 by Joseph Wenninger <jowenn@kde.org>
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 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
|
|
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 "kmultitabbar.h"
|
|
#include "kmultitabbar_p.h"
|
|
#include "moc_kmultitabbar.cpp"
|
|
#include "moc_kmultitabbar_p.cpp"
|
|
|
|
#include <QtGui/qevent.h>
|
|
#include <QtGui/QLayout>
|
|
#include <QtGui/QPainter>
|
|
#include <QtGui/QFontMetrics>
|
|
#include <QtGui/QStyle>
|
|
#include <QtGui/qstyleoption.h>
|
|
|
|
#include <kiconloader.h>
|
|
#include <kdebug.h>
|
|
#include <QtGui/QApplication>
|
|
#include <math.h>
|
|
|
|
/**
|
|
A bit of an overview about what's going on here:
|
|
There are two sorts of things that can be in the tab bar: tabs and regular
|
|
buttons. The former are managed by KMultiTabBarInternal, the later
|
|
by the KMultiTabBar itself.
|
|
*/
|
|
|
|
class KMultiTabBarPrivate
|
|
{
|
|
public:
|
|
class KMultiTabBarInternal *m_internal;
|
|
QBoxLayout *m_l;
|
|
QFrame *m_btnTabSep;
|
|
QList<KMultiTabBarButton*> m_buttons;
|
|
KMultiTabBar::KMultiTabBarPosition m_position;
|
|
};
|
|
|
|
|
|
KMultiTabBarInternal::KMultiTabBarInternal(QWidget *parent, KMultiTabBar::KMultiTabBarPosition pos):QFrame(parent)
|
|
{
|
|
m_position = pos;
|
|
if (pos == KMultiTabBar::Left || pos == KMultiTabBar::Right)
|
|
mainLayout=new QVBoxLayout(this);
|
|
else
|
|
mainLayout=new QHBoxLayout(this);
|
|
mainLayout->setMargin(0);
|
|
mainLayout->setSpacing(0);
|
|
mainLayout->addStretch();
|
|
setFrameStyle(NoFrame);
|
|
setBackgroundRole(QPalette::Background);
|
|
}
|
|
|
|
KMultiTabBarInternal::~KMultiTabBarInternal()
|
|
{
|
|
qDeleteAll(m_tabs);
|
|
m_tabs.clear();
|
|
}
|
|
|
|
void KMultiTabBarInternal::setStyle(enum KMultiTabBar::KMultiTabBarStyle style)
|
|
{
|
|
m_style=style;
|
|
for (int i=0;i<m_tabs.count();i++)
|
|
m_tabs.at(i)->setStyle(m_style);
|
|
|
|
updateGeometry();
|
|
}
|
|
|
|
void KMultiTabBarInternal::mousePressEvent(QMouseEvent *ev)
|
|
{
|
|
ev->ignore();
|
|
}
|
|
|
|
KMultiTabBarTab* KMultiTabBarInternal::tab(int id) const
|
|
{
|
|
QListIterator<KMultiTabBarTab*> it(m_tabs);
|
|
while (it.hasNext()) {
|
|
KMultiTabBarTab *tab = it.next();
|
|
if (tab->id()==id) return tab;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int KMultiTabBarInternal::appendTab(const QPixmap &pic, int id, const QString& text)
|
|
{
|
|
KMultiTabBarTab *tab;
|
|
m_tabs.append(tab= new KMultiTabBarTab(pic,text,id,this,m_position,m_style));
|
|
|
|
// Insert before the stretch..
|
|
mainLayout->insertWidget(m_tabs.size()-1, tab);
|
|
tab->show();
|
|
return 0;
|
|
}
|
|
|
|
void KMultiTabBarInternal::removeTab(int id)
|
|
{
|
|
for (int pos=0;pos<m_tabs.count();pos++)
|
|
{
|
|
if (m_tabs.at(pos)->id()==id)
|
|
{
|
|
// remove & delete the tab
|
|
delete m_tabs.takeAt(pos);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void KMultiTabBarInternal::setPosition(enum KMultiTabBar::KMultiTabBarPosition pos)
|
|
{
|
|
m_position=pos;
|
|
for (int i=0;i<m_tabs.count();i++)
|
|
m_tabs.at(i)->setPosition(m_position);
|
|
updateGeometry();
|
|
}
|
|
|
|
// KMultiTabBarButton
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
KMultiTabBarButton::KMultiTabBarButton(const QPixmap& pic, const QString& text,
|
|
int id, QWidget *parent)
|
|
: QPushButton(QIcon(pic), text, parent), m_id(id)
|
|
{
|
|
connect(this,SIGNAL(clicked()),this,SLOT(slotClicked()));
|
|
|
|
// we can't see the focus, so don't take focus. #45557
|
|
// If keyboard navigation is wanted, then only the bar should take focus,
|
|
// and arrows could change the focused button; but generally, tabbars don't take focus anyway.
|
|
setFocusPolicy(Qt::NoFocus);
|
|
}
|
|
|
|
KMultiTabBarButton::~KMultiTabBarButton()
|
|
{
|
|
}
|
|
|
|
void KMultiTabBarButton::setText(const QString &text)
|
|
{
|
|
QPushButton::setText(text);
|
|
}
|
|
|
|
void KMultiTabBarButton::slotClicked()
|
|
{
|
|
updateGeometry();
|
|
emit clicked(m_id);
|
|
}
|
|
|
|
int KMultiTabBarButton::id() const
|
|
{
|
|
return m_id;
|
|
}
|
|
|
|
void KMultiTabBarButton::hideEvent( QHideEvent* he) {
|
|
QPushButton::hideEvent(he);
|
|
KMultiTabBar *tb=qobject_cast<KMultiTabBar*>(parentWidget());
|
|
if (tb) tb->updateSeparator();
|
|
}
|
|
|
|
void KMultiTabBarButton::showEvent( QShowEvent* he) {
|
|
QPushButton::showEvent(he);
|
|
KMultiTabBar *tb=qobject_cast<KMultiTabBar*>(parentWidget());
|
|
if (tb) tb->updateSeparator();
|
|
}
|
|
|
|
void KMultiTabBarButton::paintEvent(QPaintEvent *) {
|
|
QStyleOptionButton opt;
|
|
opt.initFrom(this);
|
|
opt.icon = icon();
|
|
opt.iconSize = iconSize();
|
|
// removes the QStyleOptionButton::HasMenu ButtonFeature
|
|
opt.features = QStyleOptionButton::Flat;
|
|
QPainter painter(this);
|
|
style()->drawControl(QStyle::CE_PushButton, &opt, &painter, this);
|
|
}
|
|
|
|
// KMultiTabBarTab
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
KMultiTabBarTab::KMultiTabBarTab(const QPixmap& pic, const QString& text,
|
|
int id, QWidget *parent,
|
|
KMultiTabBar::KMultiTabBarPosition pos,
|
|
KMultiTabBar::KMultiTabBarStyle style)
|
|
: KMultiTabBarButton(pic, text, id, parent), m_style(style), d(0)
|
|
{
|
|
m_position=pos;
|
|
setToolTip(text);
|
|
setCheckable(true);
|
|
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
|
|
// shrink down to icon only, but prefer to show text if it's there
|
|
}
|
|
|
|
KMultiTabBarTab::~KMultiTabBarTab()
|
|
{
|
|
}
|
|
|
|
void KMultiTabBarTab::setPosition(KMultiTabBar::KMultiTabBarPosition pos)
|
|
{
|
|
m_position=pos;
|
|
updateGeometry();
|
|
}
|
|
|
|
void KMultiTabBarTab::setStyle(KMultiTabBar::KMultiTabBarStyle style)
|
|
{
|
|
m_style=style;
|
|
updateGeometry();
|
|
}
|
|
|
|
QPixmap KMultiTabBarTab::iconPixmap() const
|
|
{
|
|
int iconSize = style()->pixelMetric(QStyle::PM_SmallIconSize, 0, this);
|
|
return icon().pixmap(iconSize);
|
|
}
|
|
|
|
void KMultiTabBarTab::initStyleOption(QStyleOptionToolButton* opt) const
|
|
{
|
|
opt->initFrom(this);
|
|
|
|
// Setup icon..
|
|
if (!icon().isNull()) {
|
|
opt->iconSize = iconPixmap().size();
|
|
opt->icon = icon();
|
|
}
|
|
|
|
// Should we draw text?
|
|
if (shouldDrawText())
|
|
opt->text = text();
|
|
|
|
opt->state |= QStyle::State_AutoRaise;
|
|
if (underMouse())
|
|
opt->state |= QStyle::State_MouseOver | QStyle::State_Raised;
|
|
|
|
if (isChecked())
|
|
opt->state |= QStyle::State_Sunken | QStyle::State_On;
|
|
|
|
opt->font = font();
|
|
opt->toolButtonStyle = shouldDrawText() ? Qt::ToolButtonTextBesideIcon : Qt::ToolButtonIconOnly;
|
|
opt->subControls = QStyle::SC_ToolButton;
|
|
}
|
|
|
|
QSize KMultiTabBarTab::sizeHint() const
|
|
{
|
|
return computeSizeHint(shouldDrawText());
|
|
}
|
|
|
|
QSize KMultiTabBarTab::minimumSizeHint() const
|
|
{
|
|
return computeSizeHint(false);
|
|
}
|
|
|
|
void KMultiTabBarTab::computeMargins(int* hMargin, int* vMargin) const
|
|
{
|
|
// Unfortunately, QStyle does not give us enough information to figure out
|
|
// where to place things, so we try to reverse-engineer it
|
|
QStyleOptionToolButton opt;
|
|
initStyleOption(&opt);
|
|
|
|
QPixmap iconPix = iconPixmap();
|
|
QSize trialSize = iconPix.size();
|
|
QSize expandSize = style()->sizeFromContents(QStyle::CT_ToolButton, &opt, trialSize, this);
|
|
|
|
*hMargin = (expandSize.width() - trialSize.width())/2;
|
|
*vMargin = (expandSize.height() - trialSize.height())/2;
|
|
}
|
|
|
|
QSize KMultiTabBarTab::computeSizeHint(bool withText) const
|
|
{
|
|
// Compute as horizontal first, then flip around if need be.
|
|
QStyleOptionToolButton opt;
|
|
initStyleOption(&opt);
|
|
|
|
int hMargin, vMargin;
|
|
computeMargins(&hMargin, &vMargin);
|
|
|
|
// Compute interior size, starting from pixmap..
|
|
QPixmap iconPix = iconPixmap();
|
|
QSize size = iconPix.size();
|
|
|
|
// Always include text height in computation, to avoid resizing the minor direction
|
|
// when expanding text..
|
|
QSize textSize = fontMetrics().size(0, text());
|
|
size.setHeight(qMax(size.height(), textSize.height()));
|
|
|
|
// Pick margins for major/minor direction, depending on orientation
|
|
int majorMargin = isVertical() ? vMargin : hMargin;
|
|
int minorMargin = isVertical() ? hMargin : vMargin;
|
|
|
|
size.setWidth (size.width() + 2*majorMargin);
|
|
size.setHeight(size.height() + 2*minorMargin);
|
|
|
|
if (withText)
|
|
// Add enough room for the text, and an extra major margin.
|
|
size.setWidth(size.width() + textSize.width() + majorMargin);
|
|
|
|
// flip time?
|
|
if (isVertical())
|
|
return QSize(size.height(), size.width());
|
|
else
|
|
return size;
|
|
}
|
|
|
|
void KMultiTabBarTab::setState(bool newState)
|
|
{
|
|
setChecked(newState);
|
|
updateGeometry();
|
|
}
|
|
|
|
void KMultiTabBarTab::setIcon(const QString& icon)
|
|
{
|
|
QPixmap pic=SmallIcon(icon);
|
|
setIcon(pic);
|
|
}
|
|
|
|
void KMultiTabBarTab::setIcon(const QPixmap& icon)
|
|
{
|
|
QPushButton::setIcon(icon);
|
|
}
|
|
|
|
bool KMultiTabBarTab::shouldDrawText() const
|
|
{
|
|
return (m_style==KMultiTabBar::KDEV3ICON) || isChecked();
|
|
}
|
|
|
|
bool KMultiTabBarTab::isVertical() const
|
|
{
|
|
return m_position==KMultiTabBar::Right || m_position==KMultiTabBar::Left;
|
|
}
|
|
|
|
void KMultiTabBarTab::paintEvent(QPaintEvent*) {
|
|
QPainter painter(this);
|
|
|
|
QStyleOptionToolButton opt;
|
|
initStyleOption(&opt);
|
|
|
|
// Paint bevel..
|
|
if (underMouse() || isChecked()) {
|
|
opt.text.clear();
|
|
opt.icon = QIcon();
|
|
style()->drawComplexControl(QStyle::CC_ToolButton, &opt, &painter, this);
|
|
}
|
|
|
|
int hMargin, vMargin;
|
|
computeMargins(&hMargin, &vMargin);
|
|
|
|
// We first figure out how much room we have for the text, based on
|
|
// icon size and margin, try to fit in by eliding, and perhaps
|
|
// give up on drawing the text entirely if we're too short on room
|
|
QPixmap icon = iconPixmap();
|
|
int textRoom = 0;
|
|
int iconRoom = 0;
|
|
|
|
QString t;
|
|
if (shouldDrawText()) {
|
|
if (isVertical()) {
|
|
iconRoom = icon.height() + 2*vMargin;
|
|
textRoom = height() - iconRoom - vMargin;
|
|
} else {
|
|
iconRoom = icon.width() + 2*hMargin;
|
|
textRoom = width() - iconRoom - hMargin;
|
|
}
|
|
|
|
t = painter.fontMetrics().elidedText(text(), Qt::ElideRight, textRoom);
|
|
|
|
// See whether anything is left. Qt will return either
|
|
// ... or the ellipsis unicode character, 0x2026
|
|
if (t == QLatin1String("...") || t == QChar(0x2026))
|
|
t.clear();
|
|
}
|
|
|
|
// Label time.... Simple case: no text, so just plop down the icon right in the center
|
|
// We only do this when the button never draws the text, to avoid jumps in icon position
|
|
// when resizing
|
|
if (!shouldDrawText()) {
|
|
style()->drawItemPixmap(&painter, rect(), Qt::AlignCenter | Qt::AlignVCenter, icon);
|
|
return;
|
|
}
|
|
|
|
// Now where the icon/text goes depends on text direction and tab position
|
|
QRect iconArea;
|
|
QRect labelArea;
|
|
|
|
bool bottomIcon = false;
|
|
bool rtl = layoutDirection() == Qt::RightToLeft;
|
|
if (isVertical()) {
|
|
if (m_position == KMultiTabBar::Left && !rtl)
|
|
bottomIcon = true;
|
|
if (m_position == KMultiTabBar::Right && rtl)
|
|
bottomIcon = true;
|
|
}
|
|
//alignFlags = Qt::AlignLeading | Qt::AlignVCenter;
|
|
|
|
if (isVertical()) {
|
|
if (bottomIcon) {
|
|
labelArea = QRect(0, vMargin, width(), textRoom);
|
|
iconArea = QRect(0, vMargin + textRoom, width(), iconRoom);
|
|
} else {
|
|
labelArea = QRect(0, iconRoom, width(), textRoom);
|
|
iconArea = QRect(0, 0, width(), iconRoom);
|
|
}
|
|
} else {
|
|
// Pretty simple --- depends only on RTL/LTR
|
|
if (rtl) {
|
|
labelArea = QRect(hMargin, 0, textRoom, height());
|
|
iconArea = QRect(hMargin + textRoom, 0, iconRoom, height());
|
|
} else {
|
|
labelArea = QRect(iconRoom, 0, textRoom, height());
|
|
iconArea = QRect(0, 0, iconRoom, height());
|
|
}
|
|
}
|
|
|
|
style()->drawItemPixmap(&painter, iconArea, Qt::AlignCenter | Qt::AlignVCenter, icon);
|
|
|
|
if (t.isEmpty())
|
|
return;
|
|
|
|
QRect labelPaintArea = labelArea;
|
|
|
|
if (isVertical()) {
|
|
// If we're vertical, we paint to a simple 0,0 origin rect,
|
|
// and get the transformations to get us in the right place
|
|
labelPaintArea = QRect(0, 0, labelArea.height(), labelArea.width());
|
|
|
|
QTransform tr;
|
|
|
|
if (bottomIcon) {
|
|
tr.translate(labelArea.x(), labelPaintArea.width() + labelArea.y());
|
|
tr.rotate(-90);
|
|
} else {
|
|
tr.translate(labelPaintArea.height() + labelArea.x(), labelArea.y());
|
|
tr.rotate(90);
|
|
}
|
|
painter.setTransform(tr);
|
|
}
|
|
|
|
style()->drawItemText(&painter, labelPaintArea, Qt::AlignLeading | Qt::AlignVCenter,
|
|
palette(), true, t, QPalette::ButtonText);
|
|
}
|
|
|
|
// KMultiTabBar
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
KMultiTabBar::KMultiTabBar(KMultiTabBarPosition pos, QWidget *parent)
|
|
: QWidget(parent),
|
|
d(new KMultiTabBarPrivate)
|
|
{
|
|
if (pos == Left || pos == Right)
|
|
{
|
|
d->m_l=new QVBoxLayout(this);
|
|
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding/*, true*/);
|
|
}
|
|
else
|
|
{
|
|
d->m_l=new QHBoxLayout(this);
|
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed/*, true*/);
|
|
}
|
|
d->m_l->setMargin(0);
|
|
d->m_l->setSpacing(0);
|
|
|
|
d->m_internal=new KMultiTabBarInternal(this, pos);
|
|
setPosition(pos);
|
|
setStyle(VSNET);
|
|
d->m_l->insertWidget(0,d->m_internal);
|
|
d->m_l->insertWidget(0,d->m_btnTabSep=new QFrame(this));
|
|
d->m_btnTabSep->setFixedHeight(4);
|
|
d->m_btnTabSep->setFrameStyle(QFrame::Panel | QFrame::Sunken);
|
|
d->m_btnTabSep->setLineWidth(2);
|
|
d->m_btnTabSep->hide();
|
|
|
|
updateGeometry();
|
|
}
|
|
|
|
KMultiTabBar::~KMultiTabBar()
|
|
{
|
|
qDeleteAll( d->m_buttons );
|
|
d->m_buttons.clear();
|
|
delete d;
|
|
}
|
|
|
|
int KMultiTabBar::appendButton(const QPixmap &pic, int id, QMenu *popup, const QString&)
|
|
{
|
|
KMultiTabBarButton *btn = new KMultiTabBarButton(pic, QString(), id, this);
|
|
// a button with a QMenu can have another size. Make sure the button has always the same size.
|
|
btn->setFixedWidth(btn->height());
|
|
btn->setMenu(popup);
|
|
d->m_buttons.append(btn);
|
|
d->m_l->insertWidget(0,btn);
|
|
btn->show();
|
|
d->m_btnTabSep->show();
|
|
return 0;
|
|
}
|
|
|
|
void KMultiTabBar::updateSeparator() {
|
|
bool hideSep=true;
|
|
QListIterator<KMultiTabBarButton*> it(d->m_buttons);
|
|
while (it.hasNext()){
|
|
if (it.next()->isVisibleTo(this)) {
|
|
hideSep=false;
|
|
break;
|
|
}
|
|
}
|
|
if (hideSep)
|
|
d->m_btnTabSep->hide();
|
|
else
|
|
d->m_btnTabSep->show();
|
|
}
|
|
|
|
int KMultiTabBar::appendTab(const QPixmap &pic, int id, const QString& text)
|
|
{
|
|
d->m_internal->appendTab(pic,id,text);
|
|
return 0;
|
|
}
|
|
|
|
KMultiTabBarButton* KMultiTabBar::button(int id) const
|
|
{
|
|
QListIterator<KMultiTabBarButton*> it(d->m_buttons);
|
|
while ( it.hasNext() ) {
|
|
KMultiTabBarButton *button = it.next();
|
|
if ( button->id() == id )
|
|
return button;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
KMultiTabBarTab* KMultiTabBar::tab(int id) const
|
|
{
|
|
return d->m_internal->tab(id);
|
|
}
|
|
|
|
void KMultiTabBar::removeButton(int id)
|
|
{
|
|
for (int pos=0;pos<d->m_buttons.count();pos++)
|
|
{
|
|
if (d->m_buttons.at(pos)->id()==id)
|
|
{
|
|
d->m_buttons.takeAt(pos)->deleteLater();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (d->m_buttons.count()==0)
|
|
d->m_btnTabSep->hide();
|
|
}
|
|
|
|
void KMultiTabBar::removeTab(int id)
|
|
{
|
|
d->m_internal->removeTab(id);
|
|
}
|
|
|
|
void KMultiTabBar::setTab(int id,bool state)
|
|
{
|
|
KMultiTabBarTab *ttab=tab(id);
|
|
if (ttab)
|
|
ttab->setState(state);
|
|
}
|
|
|
|
bool KMultiTabBar::isTabRaised(int id) const
|
|
{
|
|
KMultiTabBarTab *ttab=tab(id);
|
|
if (ttab)
|
|
return ttab->isChecked();
|
|
|
|
return false;
|
|
}
|
|
|
|
void KMultiTabBar::setStyle(KMultiTabBarStyle style)
|
|
{
|
|
d->m_internal->setStyle(style);
|
|
}
|
|
|
|
KMultiTabBar::KMultiTabBarStyle KMultiTabBar::tabStyle() const
|
|
{
|
|
return d->m_internal->m_style;
|
|
}
|
|
|
|
void KMultiTabBar::setPosition(KMultiTabBarPosition pos)
|
|
{
|
|
d->m_position=pos;
|
|
d->m_internal->setPosition(pos);
|
|
}
|
|
|
|
KMultiTabBar::KMultiTabBarPosition KMultiTabBar::position() const
|
|
{
|
|
return d->m_position;
|
|
}
|
|
|
|
void KMultiTabBar::fontChange(const QFont& /* oldFont */)
|
|
{
|
|
updateGeometry();
|
|
}
|
|
|
|
// vim: ts=4 sw=4 noet
|
|
// kate: indent-width 4; replace-tabs off; tab-width 4; space-indent off;
|