kwin/tabbox/tabboxview.cpp
Martin Gräßlin 608f5fab7a Fixing some regressions in the layout preview widget introduced due to the animation.
This change also includes some visual updates which fixes the black corners issue for non composited tabbox (no idea why), the hughe black border in the prview is still visible (also no idea why).

svn path=/trunk/KDE/kdebase/workspace/; revision=1070114
2010-01-04 22:24:30 +00:00

470 lines
16 KiB
C++

/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2009 Martin Gräßlin <kde@martin-graesslin.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
// own
#include "tabboxview.h"
// tabbox
#include "clientitemdelegate.h"
#include "clientmodel.h"
#include "desktopitemdelegate.h"
#include "desktopmodel.h"
#include "tabboxconfig.h"
#include "tabboxhandler.h"
// Qt
#include <QTextStream>
#include <QGridLayout>
#include <QHeaderView>
#include <QKeyEvent>
#include <QSizePolicy>
#include <QPainter>
#include <QPropertyAnimation>
// KDE
#include <kephal/screens.h>
#include <Plasma/FrameSvg>
#include <KDebug>
namespace KWin
{
namespace TabBox
{
TabBoxView::TabBoxView( QWidget* parent )
: QWidget( parent )
, m_previewUpdate( false )
{
setWindowFlags( Qt::X11BypassWindowManagerHint );
setAttribute( Qt::WA_TranslucentBackground );
QPalette pal = palette();
pal.setColor(backgroundRole(), Qt::transparent);
setPalette(pal);
m_clientModel = new ClientModel( this );
m_desktopModel = new DesktopModel( this );
m_delegate = new ClientItemDelegate( this );
m_additionalClientDelegate = new ClientItemDelegate( this );
m_additionalClientDelegate->setShowSelection( false );
m_desktopItemDelegate = new DesktopItemDelegate( this );
m_additionalDesktopDelegate = new DesktopItemDelegate( this );
m_tableView = new TabBoxMainView( this );
m_additionalView = new TabBoxAdditionalView( this );
// FrameSvg
m_frame = new Plasma::FrameSvg( this );
m_frame->setImagePath( "dialogs/background" );
m_frame->setCacheAllRenderedFrames( true );
m_frame->setEnabledBorders( Plasma::FrameSvg::AllBorders );
m_selectionFrame = new Plasma::FrameSvg( this );
m_selectionFrame->setImagePath( "widgets/viewitem" );
m_selectionFrame->setElementPrefix( "hover" );
m_selectionFrame->setCacheAllRenderedFrames( true );
m_selectionFrame->setEnabledBorders( Plasma::FrameSvg::AllBorders );
m_animation = new QPropertyAnimation( this, "selectedItem", this );
m_animation->setEasingCurve( QEasingCurve::InOutQuad );
connect( tabBox, SIGNAL(configChanged()), this, SLOT(configChanged()));
connect( m_animation, SIGNAL(valueChanged(QVariant)), SLOT(update()));
connect( m_tableView, SIGNAL(activated(QModelIndex)), SLOT(setCurrentIndex(QModelIndex)));
}
TabBoxView::~TabBoxView()
{
}
void TabBoxView::paintEvent(QPaintEvent* e)
{
// paint the background
QPainter painter( this );
painter.setRenderHint(QPainter::Antialiasing);
painter.setClipRect(e->rect());
m_frame->paintFrame( &painter );
// and the selection item
if( m_previewUpdate )
{
m_previewUpdate = false;
setCurrentIndex( m_tableView->currentIndex() );
}
m_selectionFrame->paintFrame( &painter,
m_tableView->geometry().topLeft() + m_selectedItem.topLeft() );
QWidget::paintEvent(e);
}
bool TabBoxView::event( QEvent* event )
{
if( event->type() == QEvent::Paint )
{
QPainter p( this );
p.setCompositionMode( QPainter::CompositionMode_Source );
p.fillRect( rect(), Qt::transparent );
}
return QWidget::event( event );
}
void TabBoxView::resizeEvent(QResizeEvent* event)
{
m_frame->resizeFrame( event->size() );
setMask( m_frame->mask() );
QWidget::resizeEvent(event);
}
void TabBoxView::updateGeometry()
{
if( m_tableView->model()->columnCount() == 0 || m_tableView->model()->rowCount() == 0 )
return;
QSize hint = sizeHint();
QRect screenRect = Kephal::ScreenUtils::screenGeometry( tabBox->activeScreen() );
int x = screenRect.x() + screenRect.width() * 0.5 - hint.width() * 0.5;
int y = screenRect.y() + screenRect.height() * 0.5 - hint.height() * 0.5;
setGeometry( x, y, hint.width(), hint.height() );
}
QSize TabBoxView::sizeHint() const
{
if( m_tableView->model()->columnCount() == 0 || m_tableView->model()->rowCount() == 0 )
return QSize( 0, 0 );
// calculate width and height
QSize tabBoxSize = m_tableView->sizeHint();
qreal columnWidth = tabBoxSize.width() / m_tableView->model()->columnCount();
qreal rowHeight = tabBoxSize.height() / m_tableView->model()->rowCount();
for( int i=0; i<m_tableView->model()->rowCount(); i++ )
m_tableView->setRowHeight( i, rowHeight );
// additional view
QSize additionalSize = m_additionalView->sizeHint();
for( int i=0; i<m_additionalView->model()->columnCount(); i++ )
m_additionalView->setColumnWidth( i, additionalSize.width() );
for( int i=0; i<m_additionalView->model()->rowCount(); i++ )
m_additionalView->setRowHeight( i, additionalSize.height() );
// reserve some space for borders
qreal top, bottom, left, right;
m_frame->getMargins( left, top, right, bottom );
int width = columnWidth * m_tableView->model()->columnCount() + left + right;
int height = rowHeight * m_tableView->model()->rowCount() + top + bottom;
qreal addedWidth = left + right;
// depending on layout of additional view we have to add some width or height
switch( tabBox->config().selectedItemViewPosition() )
{
case TabBoxConfig::AbovePosition: // fall through
case TabBoxConfig::BelowPosition:
if( additionalSize.width() + int(left + right) > width )
{
addedWidth += (additionalSize.width() + int(left + right) - width);
width = additionalSize.width() + int(left + right);
}
height = height + additionalSize.height();
break;
case TabBoxConfig::LeftPosition: // fall through
case TabBoxConfig::RightPosition:
width = width + additionalSize.width();
addedWidth += additionalSize.width();
height = qMax( height, additionalSize.height() + int(top + bottom) );
break;
default:
// don't add
break;
}
QRect screenRect = Kephal::ScreenUtils::screenGeometry( tabBox->activeScreen() );
width = qBound( screenRect.width() * tabBox->config().minWidth() / 100, width,
screenRect.width() );
height = qBound( screenRect.height() * tabBox->config().minHeight() / 100, height,
screenRect.height() );
if( width - addedWidth > tabBoxSize.width() )
{
columnWidth = (width - addedWidth) / m_tableView->model()->columnCount();
}
m_tableView->setMinimumWidth( width - addedWidth );
for( int i=0; i<m_tableView->model()->columnCount(); i++ )
m_tableView->setColumnWidth( i, columnWidth );
return QSize( width, height );
}
void TabBoxView::setCurrentIndex( QModelIndex index )
{
if( index.isValid() )
{
m_tableView->setCurrentIndex( index );
const QRect visualRect = m_tableView->visualRect( index );
if( m_selectedItem.isNull() )
m_selectedItem = visualRect;
if( m_animation->state() == QPropertyAnimation::Running )
{
m_animation->stop();
m_selectedItem = visualRect;
update();
}
else
{
m_animation->setStartValue( m_selectedItem );
m_animation->setEndValue( visualRect );
m_animation->start();
}
m_selectionFrame->resizeFrame( visualRect.size() );
m_additionalView->setCurrentIndex( index );
}
}
void TabBoxView::configChanged()
{
switch( tabBox->config().tabBoxMode() )
{
case TabBoxConfig::ClientTabBox:
m_tableView->setModel( m_clientModel );
m_tableView->setItemDelegate( m_delegate );
m_additionalView->setModel( m_clientModel );
m_additionalView->setItemDelegate( m_additionalClientDelegate );
break;
case TabBoxConfig::DesktopTabBox:
m_tableView->setModel( m_desktopModel );
m_tableView->setItemDelegate( m_desktopItemDelegate );
m_additionalView->setModel( m_desktopModel );
m_additionalView->setItemDelegate( m_additionalDesktopDelegate );
break;
}
QLayout* old = layout();
QLayoutItem *child;
while( old && (child = old->takeAt( 0 )) != 0 )
{
delete child;
}
delete old;
QBoxLayout *layout;
switch( tabBox->config().selectedItemViewPosition() )
{
case TabBoxConfig::AbovePosition:
{
layout = new QVBoxLayout();
QHBoxLayout* horizontalLayout1 = new QHBoxLayout();
horizontalLayout1->addStretch();
horizontalLayout1->addWidget( m_additionalView );
horizontalLayout1->addStretch();
layout->addLayout( horizontalLayout1 );
layout->addStretch();
QHBoxLayout* horizontalLayout2 = new QHBoxLayout();
horizontalLayout2->addStretch();
horizontalLayout2->addWidget( m_tableView );
horizontalLayout2->addStretch();
layout->addLayout( horizontalLayout2 );
m_additionalView->show();
break;
}
case TabBoxConfig::BelowPosition:
{
layout = new QVBoxLayout();
QHBoxLayout* horizontalLayout1 = new QHBoxLayout();
horizontalLayout1->addStretch();
horizontalLayout1->addWidget( m_tableView );
horizontalLayout1->addStretch();
layout->addLayout( horizontalLayout1 );
layout->addStretch();
QHBoxLayout* horizontalLayout2 = new QHBoxLayout();
horizontalLayout2->addStretch();
horizontalLayout2->addWidget( m_additionalView );
horizontalLayout2->addStretch();
layout->addLayout( horizontalLayout2 );
m_additionalView->show();
break;
}
case TabBoxConfig::LeftPosition:
{
layout = new QHBoxLayout();
QVBoxLayout* verticalLayout1 = new QVBoxLayout();
verticalLayout1->addStretch();
verticalLayout1->addWidget( m_additionalView );
verticalLayout1->addStretch();
layout->addLayout( verticalLayout1 );
layout->addStretch();
QVBoxLayout* verticalLayout2 = new QVBoxLayout();
verticalLayout2->addStretch();
verticalLayout2->addWidget( m_tableView );
verticalLayout2->addStretch();
layout->addLayout( verticalLayout2 );
m_additionalView->show();
break;
}
case TabBoxConfig::RightPosition:
{
layout = new QHBoxLayout();
QVBoxLayout* verticalLayout1 = new QVBoxLayout();
verticalLayout1->addStretch();
verticalLayout1->addWidget( m_tableView );
verticalLayout1->addStretch();
layout->addLayout( verticalLayout1 );
layout->addStretch();
QVBoxLayout* verticalLayout2 = new QVBoxLayout();
verticalLayout2->addStretch();
verticalLayout2->addWidget( m_additionalView );
verticalLayout2->addStretch();
layout->addLayout( verticalLayout2 );
m_additionalView->show();
break;
}
default:
{
layout = new QVBoxLayout();
layout->addStretch();
layout->addWidget( m_tableView );
layout->addStretch();
m_additionalView->hide();
break;
}
}
setLayout( layout );
if( m_preview )
m_previewUpdate = true;
}
QModelIndex TabBoxView::indexAt( QPoint pos )
{
return m_tableView->indexAt( pos );
}
void TabBoxView::setPreview( bool preview )
{
m_preview = preview;
if( preview )
m_frame->setImagePath( "dialogs/opaque/background" );
}
/********************************************************
* TabBoxMainView
********************************************************/
TabBoxMainView::TabBoxMainView(QWidget* parent)
: QTableView(parent)
{
setFrameStyle( QFrame::NoFrame );
setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
viewport()->setAutoFillBackground( false );
// adjust table view to needs of tabbox
setShowGrid( false );
horizontalHeader()->hide();
verticalHeader()->hide();
setSelectionMode( QAbstractItemView::SingleSelection );
setSelectionBehavior( QAbstractItemView::SelectItems );
setHorizontalScrollMode( QAbstractItemView::ScrollPerItem );
setVerticalScrollMode( QAbstractItemView::ScrollPerItem );
setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding );
}
TabBoxMainView::~TabBoxMainView()
{
}
QSize TabBoxMainView::sizeHint() const
{
int maxWidth = 0;
int minWidth = sizeHintForColumn( 0 );
int maxHeight = 0;
int minHeight = sizeHintForRow( 0 );
for( int i=0; i<model()->columnCount(); i++ )
{
minWidth = qMin( minWidth, sizeHintForColumn( i ) );
maxWidth = qMax( maxWidth, sizeHintForColumn( i ) );
}
for( int i=0; i<model()->rowCount(); i++ )
{
minHeight = qMin( minHeight, sizeHintForRow( i ) );
maxHeight = qMax( maxHeight, sizeHintForRow( i ) );
}
qreal columnWidth = (minWidth + qreal(maxWidth - minWidth) / 2.0 );
qreal rowHeight = (minHeight + qreal(maxHeight - minHeight) / 2.0 );
return QSize( columnWidth * model()->columnCount(),
rowHeight * model()->rowCount() );
}
QModelIndex TabBoxMainView::moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
{
Q_UNUSED( cursorAction )
Q_UNUSED( modifiers )
return currentIndex();
}
/********************************************************
* TabBoxAdditonalView
********************************************************/
TabBoxAdditionalView::TabBoxAdditionalView(QWidget* parent)
: QTableView(parent)
{
setFrameStyle( QFrame::NoFrame );
setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
viewport()->setAutoFillBackground( false );
// adjust table view to needs of tabbox
setShowGrid( false );
horizontalHeader()->hide();
verticalHeader()->hide();
setSelectionMode( QAbstractItemView::SingleSelection );
setSelectionBehavior( QAbstractItemView::SelectItems );
setHorizontalScrollMode( QAbstractItemView::ScrollPerItem );
setVerticalScrollMode( QAbstractItemView::ScrollPerItem );
setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
}
TabBoxAdditionalView::~TabBoxAdditionalView()
{
}
QSize TabBoxAdditionalView::sizeHint() const
{
int maxWidth = 0;
int minWidth = sizeHintForColumn( 0 );
int maxHeight = 0;
int minHeight = sizeHintForRow( 0 );
for( int i=0; i<model()->columnCount(); i++ )
{
minWidth = qMin( minWidth, sizeHintForColumn( i ) );
maxWidth = qMax( maxWidth, sizeHintForColumn( i ) );
}
for( int i=0; i<model()->rowCount(); i++ )
{
minHeight = qMin( minHeight, sizeHintForRow( i ) );
maxHeight = qMax( maxHeight, sizeHintForRow( i ) );
}
qreal columnWidth = (minWidth + qreal(maxWidth - minWidth) / 2.0 );
qreal rowHeight = (minHeight + qreal(maxHeight - minHeight) / 2.0 );
return QSize( columnWidth, rowHeight );
}
QModelIndex TabBoxAdditionalView::moveCursor( QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers )
{
Q_UNUSED( cursorAction )
Q_UNUSED( modifiers )
return currentIndex();
}
void TabBoxAdditionalView::wheelEvent( QWheelEvent* event )
{
Q_UNUSED( event )
}
} // namespace Tabbox
} // namespace KWin
#include "tabboxview.moc"