TabBox in QML

All the default layouts (informative, compact, text, small and big icons)
are rewritten in QML and replace the ListView used before. The old code
is still around for the desktop switching modes which are not yet ported.

Next steps include to update the configuration module to not show now
obsoleted settings as well as providing a better way to choose the layout.

REVIEW: 102948
This commit is contained in:
Martin Gräßlin 2011-10-30 16:07:14 +01:00
parent ebd0d9303b
commit aa17081fe8
14 changed files with 1188 additions and 15 deletions

View file

@ -139,6 +139,7 @@ if(KWIN_BUILD_TABBOX)
tabbox/tabbox.cpp
tabbox/clientitemdelegate.cpp
tabbox/clientmodel.cpp
tabbox/declarative.cpp
tabbox/desktopitemdelegate.cpp
tabbox/desktopmodel.cpp
tabbox/itemlayoutconfig.cpp
@ -195,7 +196,7 @@ if(KWIN_BUILD_SCRIPTING)
endif(KWIN_BUILD_SCRIPTING)
if(KWIN_BUILD_TABBOX)
set(kwinLibs ${kwinLibs} ${QT_QTXML_LIBRARY})
set(kwinLibs ${kwinLibs} ${QT_QTXML_LIBRARY} ${QT_QTDECLARATIVE_LIBRARY} kdeclarative)
endif(KWIN_BUILD_TABBOX)
kde4_add_kdeinit_executable( kwin ${kwin_KDEINIT_SRCS})
@ -246,5 +247,14 @@ install( FILES kwin.kcfg DESTINATION ${KCFG_INSTALL_DIR} )
install( FILES kwin.notifyrc DESTINATION ${DATA_INSTALL_DIR}/kwin )
install( FILES org.kde.KWin.xml DESTINATION ${DBUS_INTERFACES_INSTALL_DIR} )
install( FILES tabbox/DefaultTabBoxLayouts.xml DESTINATION ${DATA_INSTALL_DIR}/kwin )
install( FILES
tabbox/qml/informative.qml
tabbox/qml/big_icons.qml
tabbox/qml/compact.qml
tabbox/qml/small_icons.qml
tabbox/qml/tabbox.qml
tabbox/qml/text.qml
tabbox/qml/IconTabBox.qml
DESTINATION ${DATA_INSTALL_DIR}/kwin/tabbox )
kde4_install_icons( ${ICON_INSTALL_DIR} )

View file

@ -8,6 +8,7 @@ set(kcm_kwintabbox_PART_SRCS
previewhandlerimpl.cpp
${KDEBASE_WORKSPACE_SOURCE_DIR}/kwin/tabbox/clientitemdelegate.cpp
${KDEBASE_WORKSPACE_SOURCE_DIR}/kwin/tabbox/clientmodel.cpp
${KDEBASE_WORKSPACE_SOURCE_DIR}/kwin/tabbox/declarative.cpp
${KDEBASE_WORKSPACE_SOURCE_DIR}/kwin/tabbox/desktopitemdelegate.cpp
${KDEBASE_WORKSPACE_SOURCE_DIR}/kwin/tabbox/desktopmodel.cpp
${KDEBASE_WORKSPACE_SOURCE_DIR}/kwin/tabbox/itemlayoutconfig.cpp
@ -20,7 +21,7 @@ kde4_add_ui_files( kcm_kwintabbox_PART_SRCS layoutconfig.ui )
kde4_add_plugin(kcm_kwintabbox ${kcm_kwintabbox_PART_SRCS})
target_link_libraries(kcm_kwintabbox ${KDE4_KDEUI_LIBS} ${KDE4_KCMUTILS_LIBS} ${KDE4_PLASMA_LIBS} ${X11_LIBRARIES} ${QT_QTXML_LIBRARY} kephal )
target_link_libraries(kcm_kwintabbox ${KDE4_KDEUI_LIBS} ${KDE4_KCMUTILS_LIBS} ${KDE4_PLASMA_LIBS} ${X11_LIBRARIES} ${QT_QTXML_LIBRARY} kephal ${QT_QTDECLARATIVE_LIBRARY} kdeclarative )
install(TARGETS kcm_kwintabbox DESTINATION ${PLUGIN_INSTALL_DIR} )

View file

@ -38,6 +38,11 @@ namespace TabBox
ClientModel::ClientModel(QObject* parent)
: QAbstractItemModel(parent)
{
QHash<int, QByteArray> roles;
roles[CaptionRole] = "caption";
roles[DesktopNameRole] = "desktopName";
roles[MinimizedRole] = "minimized";
setRoleNames(roles);
}
ClientModel::~ClientModel()
@ -79,6 +84,17 @@ QVariant ClientModel::data(const QModelIndex& index, int role) const
}
}
QString ClientModel::longestCaption() const
{
QString caption;
foreach (TabBoxClient *client, m_clientList) {
if (client->caption().size() > caption.size()) {
caption = client->caption();
}
}
return caption;
}
int ClientModel::columnCount(const QModelIndex& parent) const
{
Q_UNUSED(parent)

View file

@ -63,6 +63,7 @@ public:
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const;
virtual QModelIndex parent(const QModelIndex& child) const;
virtual QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const;
QString longestCaption() const;
/**
* @param client The TabBoxClient whose index should be returned

195
tabbox/declarative.cpp Normal file
View file

@ -0,0 +1,195 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2011 Martin Gräßlin <mgraesslin@kde.org>
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 "declarative.h"
#include "tabboxhandler.h"
#include "clientmodel.h"
// Qt
#include <QtDeclarative/qdeclarative.h>
#include <QtDeclarative/QDeclarativeContext>
#include <QtDeclarative/QDeclarativeEngine>
#include <QtGui/QGraphicsObject>
#include <QtGui/QResizeEvent>
// include KDE
#include <KDE/KDebug>
#include <KDE/KIconEffect>
#include <KDE/KIconLoader>
#include <KDE/KStandardDirs>
#include <KDE/Plasma/FrameSvg>
#include <KDE/Plasma/Theme>
#include <KDE/Plasma/WindowEffects>
#include <kdeclarative.h>
#include <kephal/screens.h>
namespace KWin
{
namespace TabBox
{
ImageProvider::ImageProvider(QAbstractItemModel *model)
: QDeclarativeImageProvider(QDeclarativeImageProvider::Pixmap)
, m_model(model)
{
}
QPixmap ImageProvider::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize)
{
bool ok = false;
QStringList parts = id.split('/');
const int row = parts.first().toInt(&ok);
if (!ok) {
return QDeclarativeImageProvider::requestPixmap(id, size, requestedSize);
}
const QModelIndex index = m_model->index(row, 0);
if (!index.isValid()) {
return QDeclarativeImageProvider::requestPixmap(id, size, requestedSize);
}
TabBoxClient* client = static_cast< TabBoxClient* >(index.model()->data(index, ClientModel::ClientRole).value<void *>());
QSize s(32, 32);
if (requestedSize.isValid()) {
s = requestedSize;
}
*size = s;
QPixmap icon = client->icon(s);
if (parts.size() > 2) {
KIconEffect *effect = KIconLoader::global()->iconEffect();
KIconLoader::States state = KIconLoader::DefaultState;
if (parts.at(2) == QLatin1String("selected")) {
state = KIconLoader::ActiveState;
} else if (parts.at(2) == QLatin1String("disabled")) {
state = KIconLoader::DisabledState;
}
icon = effect->apply(icon, KIconLoader::Desktop, state);
}
return icon;
}
DeclarativeView::DeclarativeView(QAbstractItemModel *model, QWidget *parent)
: QDeclarativeView(parent)
, m_model(model)
, m_currentScreenGeometry()
, m_frame(new Plasma::FrameSvg(this))
, m_currentLayout()
{
setAttribute(Qt::WA_TranslucentBackground);
setWindowFlags(Qt::X11BypassWindowManagerHint);
setResizeMode(QDeclarativeView::SizeViewToRootObject);
QPalette pal = palette();
pal.setColor(backgroundRole(), Qt::transparent);
setPalette(pal);
foreach (const QString &importPath, KGlobal::dirs()->findDirs("module", "imports")) {
engine()->addImportPath(importPath);
}
engine()->addImageProvider(QLatin1String("client"), new ImageProvider(model));
KDeclarative kdeclarative;
kdeclarative.setDeclarativeEngine(engine());
kdeclarative.initialize();
kdeclarative.setupBindings();
rootContext()->setContextProperty("clientModel", model);
updateQmlSource();
// FrameSvg
m_frame->setImagePath("dialogs/background");
m_frame->setCacheAllRenderedFrames(true);
m_frame->setEnabledBorders(Plasma::FrameSvg::AllBorders);
connect(tabBox, SIGNAL(configChanged()), SLOT(updateQmlSource()));
}
void DeclarativeView::showEvent(QShowEvent *event)
{
m_currentScreenGeometry = Kephal::ScreenUtils::screenGeometry(tabBox->activeScreen());
rootObject()->setProperty("screenWidth", m_currentScreenGeometry.width());
rootObject()->setProperty("screenHeight", m_currentScreenGeometry.height());
rootObject()->setProperty("allDesktops", tabBox->config().tabBoxMode() == TabBoxConfig::ClientTabBox &&
((tabBox->config().clientListMode() == TabBoxConfig::AllDesktopsClientList) ||
(tabBox->config().clientListMode() == TabBoxConfig::AllDesktopsApplicationList)));
rootObject()->setProperty("longestCaption", static_cast<ClientModel*>(m_model)->longestCaption());
if (QObject *item = rootObject()->findChild<QObject*>("listView")) {
item->setProperty("currentIndex", tabBox->first().row());
}
slotUpdateGeometry();
QGraphicsView::showEvent(event);
}
void DeclarativeView::resizeEvent(QResizeEvent *event)
{
m_frame->resizeFrame(event->size());
if (Plasma::Theme::defaultTheme()->windowTranslucencyEnabled()) {
// blur background
Plasma::WindowEffects::enableBlurBehind(winId(), true, m_frame->mask());
Plasma::WindowEffects::overrideShadow(winId(), true);
} else {
// do not trim to mask with compositing enabled, otherwise shadows are cropped
setMask(m_frame->mask());
}
QDeclarativeView::resizeEvent(event);
}
void DeclarativeView::slotUpdateGeometry()
{
const int width = rootObject()->property("width").toInt();
const int height = rootObject()->property("height").toInt();
setGeometry(m_currentScreenGeometry.x() + static_cast<qreal>(m_currentScreenGeometry.width()) * 0.5 - static_cast<qreal>(width) * 0.5,
m_currentScreenGeometry.y() + static_cast<qreal>(m_currentScreenGeometry.height()) * 0.5 - static_cast<qreal>(height) * 0.5,
width, height);
}
void DeclarativeView::setCurrentIndex(const QModelIndex &index)
{
if (QObject *item = rootObject()->findChild<QObject*>("listView")) {
item->setProperty("currentIndex", index.row());
}
}
QModelIndex DeclarativeView::indexAt(const QPoint &pos) const
{
if (QObject *item = rootObject()->findChild<QObject*>("listView")) {
QVariant returnedValue;
QVariant xPos(pos.x());
QVariant yPos(pos.y());
QMetaObject::invokeMethod(item, "indexAtMousePos", Q_RETURN_ARG(QVariant, returnedValue), Q_ARG(QVariant, QVariant(pos)));
if (!returnedValue.canConvert<int>()) {
return QModelIndex();
}
return m_model->index(returnedValue.toInt(), 0);
}
return QModelIndex();
}
void DeclarativeView::updateQmlSource()
{
if (tabBox->config().layoutName() == m_currentLayout) {
return;
}
m_currentLayout = tabBox->config().layoutName();
setSource(QUrl(KStandardDirs::locate("data", "kwin/tabbox/tabbox.qml")));
QString file = KStandardDirs::locate("data", "kwin/tabbox/" + m_currentLayout.toLower().replace(' ', '_') + ".qml");
if (file.isNull()) {
// fallback to default
file = KStandardDirs::locate("data", "kwin/tabbox/informative.qml");
}
rootObject()->setProperty("source", QUrl(file));
}
} // namespace TabBox
} // namespace KWin

77
tabbox/declarative.h Normal file
View file

@ -0,0 +1,77 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2011 Martin Gräßlin <mgraesslin@kde.org>
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/>.
*********************************************************************/
#ifndef KWIN_TABBOX_DECLARATIVE_H
#define KWIN_TABBOX_DECLARATIVE_H
// includes
#include <QtDeclarative/QDeclarativeImageProvider>
#include <QtDeclarative/QDeclarativeView>
// forward declaration
class QAbstractItemModel;
class QModelIndex;
class QPos;
namespace Plasma
{
class FrameSvg;
}
namespace KWin
{
namespace TabBox
{
class ImageProvider : public QDeclarativeImageProvider
{
public:
ImageProvider(QAbstractItemModel *model);
virtual QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize);
private:
QAbstractItemModel *m_model;
};
class DeclarativeView : public QDeclarativeView
{
Q_OBJECT
public:
DeclarativeView(QAbstractItemModel *model, QWidget *parent = NULL);
virtual void showEvent(QShowEvent *event);
virtual void resizeEvent(QResizeEvent *event);
void setCurrentIndex(const QModelIndex &index);
QModelIndex indexAt(const QPoint &pos) const;
public Q_SLOTS:
void slotUpdateGeometry();
private Q_SLOTS:
void updateQmlSource();
private:
QAbstractItemModel *m_model;
QRect m_currentScreenGeometry;
/**
* Background Frame required for setting the blur mask
*/
Plasma::FrameSvg* m_frame;
QString m_currentLayout;
};
} // namespace TabBox
} // namespace KWin
#endif

106
tabbox/qml/IconTabBox.qml Normal file
View file

@ -0,0 +1,106 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2011 Martin Gräßlin <mgraesslin@kde.org>
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/>.
*********************************************************************/
import QtQuick 1.0
import org.kde.plasma.core 0.1 as PlasmaCore
import org.kde.qtextracomponents 0.1
Item {
id: iconsTabBox
property int iconSize
property int imagePathPrefix: (new Date()).getTime()
property alias count: iconsListView.count
property alias margins: hoverItem.margins
function setModel(model) {
iconsListView.model = model;
iconsListView.imageId++;
}
function modelChanged() {
iconsListView.imageId++;
}
PlasmaCore.Theme {
id: theme
}
// just to get the margin sizes
PlasmaCore.FrameSvgItem {
id: hoverItem
imagePath: "widgets/viewitem"
prefix: "hover"
visible: false
}
// delegate
Component {
id: listDelegate
Item {
id: delegateItem
width: iconSize + hoverItem.margins.left + hoverItem.margins.right
height: iconSize + hoverItem.margins.top + hoverItem.margins.bottom
Image {
id: iconItem
source: "image://client/" + index + "/" + iconsTabBox.imagePathPrefix + "-" + iconsListView.imageId + (index == iconsListView.currentIndex ? "/selected" : "")
sourceSize {
width: iconSize
height: iconSize
}
anchors {
fill: parent
leftMargin: hoverItem.margins.left
rightMargin: hoverItem.margins.right
topMargin: hoverItem.margins.top
bottomMargin: hoverItem.margins.bottom
}
}
}
}
ListView {
/**
* Called from C++ to get the index at a mouse pos.
**/
function indexAtMousePos(pos) {
return iconsListView.indexAt(pos.x, pos.y);
}
id: iconsListView
objectName: "listView"
orientation: ListView.Horizontal
// used for image provider URL to trick Qt into reloading icons when the model changes
property int imageId: 0
anchors {
fill: parent
}
clip: true
delegate: listDelegate
highlight: PlasmaCore.FrameSvgItem {
id: highlightItem
imagePath: "widgets/viewitem"
prefix: "hover"
width: iconSize + margins.left + margins.right
height: iconSize + margins.top + margins.bottom
}
MouseArea {
anchors.fill: parent
onClicked: iconsListView.currentIndex = iconsListView.indexAt(mouse.x, mouse.y)
}
}
}

58
tabbox/qml/big_icons.qml Normal file
View file

@ -0,0 +1,58 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2011 Martin Gräßlin <mgraesslin@kde.org>
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/>.
*********************************************************************/
import QtQuick 1.0
import org.kde.plasma.core 0.1 as PlasmaCore
import org.kde.qtextracomponents 0.1
Item {
id: bigIconsTabBox
property int screenWidth : 0
property int screenHeight : 0
property int imagePathPrefix: (new Date()).getTime()
width: Math.min(Math.max(screenWidth * 0.3, (icons.iconSize + icons.margins.left + icons.margins.right) * icons.count + background.margins.left + background.margins.bottom), screenWidth * 0.9)
height: Math.min(Math.max(screenHeight * 0.05, icons.iconSize + icons.margins.top + icons.margins.bottom + background.margins.top + background.margins.bottom), screenHeight * 0.5)
function setModel(model) {
icons.setModel(model);
}
function modelChanged() {
icons.modelChanged();
}
PlasmaCore.FrameSvgItem {
id: background
anchors.fill: parent
imagePath: "dialogs/background"
}
IconTabBox {
id: icons
iconSize: 64
anchors {
fill: parent
topMargin: background.margins.top
rightMargin: background.margins.right
bottomMargin: background.margins.bottom
leftMargin: background.margins.left
}
}
}

187
tabbox/qml/compact.qml Normal file
View file

@ -0,0 +1,187 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2011 Martin Gräßlin <mgraesslin@kde.org>
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/>.
*********************************************************************/
import QtQuick 1.0
import org.kde.plasma.core 0.1 as PlasmaCore
import org.kde.qtextracomponents 0.1
Item {
id: compactTabBox
property int screenWidth : 0
property int screenHeight : 0
property string longestCaption: ""
property int imagePathPrefix: (new Date()).getTime()
width: Math.min(Math.max(screenWidth * 0.2, compactListView.maxRowWidth), screenWidth * 0.8)
height: Math.min(Math.max(screenHeight * 0.2, compactListView.rowHeight * compactListView.count + background.margins.top + background.margins.bottom), screenHeight * 0.8)
property int textMargin: 2
onLongestCaptionChanged: {
compactListView.maxRowWidth = compactListView.calculateMaxRowWidth();
}
function setModel(model) {
compactListView.model = model;
compactListView.maxRowWidth = compactListView.calculateMaxRowWidth();
compactListView.imageId++;
}
function modelChanged() {
compactListView.imageId++;
}
/**
* Returns the caption with adjustments for minimized items.
* @param caption the original caption
* @param mimized whether the item is minimized
* @return Caption adjusted for minimized state
**/
function itemCaption(caption, minimized) {
var text = caption;
if (minimized) {
text = "(" + text + ")";
}
return text;
}
PlasmaCore.Theme {
id: theme
}
// just to get the margin sizes
PlasmaCore.FrameSvgItem {
id: hoverItem
imagePath: "widgets/viewitem"
prefix: "hover"
visible: false
}
PlasmaCore.FrameSvgItem {
id: background
anchors.fill: parent
imagePath: "dialogs/background"
}
// delegate
Component {
id: listDelegate
Item {
id: delegateItem
width: compactListView.width
height: compactListView.rowHeight
Image {
id: iconItem
source: "image://client/" + index + "/" + compactTabBox.imagePathPrefix + "-" + compactListView.imageId + (index == compactListView.currentIndex ? "/selected" : "/disabled")
width: 16
height: 16
anchors {
verticalCenter: parent.verticalCenter
left: parent.left
leftMargin: hoverItem.margins.left
}
}
Text {
id: captionItem
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignBottom
text: itemCaption(caption, minimized)
font.bold: true
font.italic: minimized
color: theme.textColor
elide: Text.ElideMiddle
anchors {
left: iconItem.right
right: parent.right
top: parent.top
bottom: parent.bottom
topMargin: hoverItem.margins.top
rightMargin: hoverItem.margins.right
bottomMargin: hoverItem.margins.bottom
leftMargin: 2 * compactTabBox.textMargin
}
}
}
}
ListView {
function calculateMaxRowWidth() {
var width = 0;
var textElement = Qt.createQmlObject(
'import Qt 4.7;'
+ 'Text {\n'
+ ' text: "' + itemCaption(compactTabBox.longestCaption, true) + '"\n'
+ ' font.bold: true\n'
+ ' visible: false\n'
+ '}',
compactListView, "calculateMaxRowWidth");
width = Math.max(textElement.width, width);
textElement.destroy();
return width + 16 + 2 * compactTabBox.textMargin + hoverItem.margins.right + hoverItem.margins.left + background.margins.left + background.margins.right;
}
/**
* Calculates the height of one row based on the text height and icon size.
* @return Row height
**/
function calcRowHeight() {
var textElement = Qt.createQmlObject(
'import Qt 4.7;'
+ 'Text {\n'
+ ' text: "Some Text"\n'
+ ' font.bold: true\n'
+ ' visible: false\n'
+ '}',
compactListView, "calcRowHeight");
var height = textElement.height;
textElement.destroy();
// icon size or two text elements and margins and hoverItem margins
return Math.max(16, height + hoverItem.margins.top + hoverItem.margins.bottom);
}
/**
* Called from C++ to get the index at a mouse pos.
**/
function indexAtMousePos(pos) {
return compactListView.indexAt(pos.x, pos.y);
}
id: compactListView
objectName: "listView"
// the maximum text width + icon item width (32 + 4 margin) + margins for hover item + margins for background
property int maxRowWidth: calculateMaxRowWidth()
property int rowHeight: calcRowHeight()
// used for image provider URL to trick Qt into reloading icons when the model changes
property int imageId: 0
anchors {
fill: parent
topMargin: background.margins.top
leftMargin: background.margins.left
rightMargin: background.margins.right
bottomMargin: background.margins.bottom
}
clip: true
delegate: listDelegate
highlight: PlasmaCore.FrameSvgItem {
id: highlightItem
imagePath: "widgets/viewitem"
prefix: "hover"
width: compactListView.width
}
MouseArea {
anchors.fill: parent
onClicked: compactListView.currentIndex = compactListView.indexAt(mouse.x, mouse.y)
}
}
}

203
tabbox/qml/informative.qml Normal file
View file

@ -0,0 +1,203 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2011 Martin Gräßlin <mgraesslin@kde.org>
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/>.
*********************************************************************/
import QtQuick 1.0
import org.kde.plasma.core 0.1 as PlasmaCore
import org.kde.qtextracomponents 0.1
Item {
id: informativeTabBox
property int screenWidth : 0
property int screenHeight : 0
property bool allDesktops: true
property string longestCaption: ""
property int imagePathPrefix: (new Date()).getTime()
width: Math.min(Math.max(screenWidth * 0.2, listView.maxRowWidth), screenWidth * 0.8)
height: Math.min(Math.max(screenHeight * 0.2, listView.rowHeight * listView.count + background.margins.top + background.margins.bottom), screenHeight * 0.8)
property int textMargin: 2
onLongestCaptionChanged: {
listView.maxRowWidth = listView.calculateMaxRowWidth();
}
function setModel(model) {
listView.model = model;
listView.maxRowWidth = listView.calculateMaxRowWidth();
listView.imageId++;
}
function modelChanged() {
listView.imageId++;
}
/**
* Returns the caption with adjustments for minimized items.
* @param caption the original caption
* @param mimized whether the item is minimized
* @return Caption adjusted for minimized state
**/
function itemCaption(caption, minimized) {
var text = caption;
if (minimized) {
text = "(" + text + ")";
}
return text;
}
PlasmaCore.Theme {
id: theme
}
// just to get the margin sizes
PlasmaCore.FrameSvgItem {
id: hoverItem
imagePath: "widgets/viewitem"
prefix: "hover"
visible: false
}
PlasmaCore.FrameSvgItem {
id: background
anchors.fill: parent
imagePath: "dialogs/background"
}
// delegate
Component {
id: listDelegate
Item {
id: delegateItem
width: listView.width
height: listView.rowHeight
Image {
id: iconItem
source: "image://client/" + index + "/" + informativeTabBox.imagePathPrefix + "-" + listView.imageId + (index == listView.currentIndex ? "/selected" : "/disabled")
width: 32
height: 32
anchors {
verticalCenter: parent.verticalCenter
left: parent.left
leftMargin: hoverItem.margins.left
}
}
Text {
id: captionItem
horizontalAlignment: Text.AlignHCenter
text: itemCaption(caption, minimized)
font.bold: true
font.italic: minimized
color: theme.textColor
elide: Text.ElideMiddle
anchors {
left: iconItem.right
right: parent.right
top: parent.top
topMargin: informativeTabBox.textMargin + hoverItem.margins.top
rightMargin: hoverItem.margins.right
}
}
Text {
id: desktopNameItem
horizontalAlignment: Text.AlignHCenter
text: desktopName
font.bold: false
font.italic: true
color: theme.textColor
elide: Text.ElideMiddle
visible: informativeTabBox.allDesktops
anchors {
left: iconItem.right
right: parent.right
top: captionItem.bottom
topMargin: informativeTabBox.textMargin
bottom: parent.bottom
bottomMargin: informativeTabBox.textMargin + hoverItem.margins.bottom
rightMargin: hoverItem.margins.right
}
}
}
}
ListView {
function calculateMaxRowWidth() {
var width = 0;
var textElement = Qt.createQmlObject(
'import Qt 4.7;'
+ 'Text {\n'
+ ' text: "' + itemCaption(informativeTabBox.longestCaption, true) + '"\n'
+ ' font.bold: true\n'
+ ' visible: false\n'
+ '}',
listView, "calculateMaxRowWidth");
width = Math.max(textElement.width, width);
textElement.destroy();
return width + 32 + hoverItem.margins.right + hoverItem.margins.left + background.margins.left + background.margins.right;
}
/**
* Calculates the height of one row based on the text height and icon size.
* @return Row height
**/
function calcRowHeight() {
var textElement = Qt.createQmlObject(
'import Qt 4.7;'
+ 'Text {\n'
+ ' text: "Some Text"\n'
+ ' font.bold: true\n'
+ ' visible: false\n'
+ '}',
listView, "calcRowHeight");
var height = textElement.height;
textElement.destroy();
// icon size or two text elements and margins and hoverItem margins
return Math.max(32, height*2 + informativeTabBox.textMargin * 3 + hoverItem.margins.top + hoverItem.margins.bottom);
}
/**
* Called from C++ to get the index at a mouse pos.
**/
function indexAtMousePos(pos) {
return listView.indexAt(pos.x, pos.y);
}
id: listView
objectName: "listView"
// the maximum text width + icon item width (32 + 4 margin) + margins for hover item + margins for background
property int maxRowWidth: calculateMaxRowWidth()
property int rowHeight: calcRowHeight()
// used for image provider URL to trick Qt into reloading icons when the model changes
property int imageId: 0
anchors {
fill: parent
topMargin: background.margins.top
leftMargin: background.margins.left
rightMargin: background.margins.right
bottomMargin: background.margins.bottom
}
clip: true
delegate: listDelegate
highlight: PlasmaCore.FrameSvgItem {
id: highlightItem
imagePath: "widgets/viewitem"
prefix: "hover"
width: listView.width
}
MouseArea {
anchors.fill: parent
onClicked: listView.currentIndex = listView.indexAt(mouse.x, mouse.y)
}
}
}

View file

@ -0,0 +1,58 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2011 Martin Gräßlin <mgraesslin@kde.org>
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/>.
*********************************************************************/
import QtQuick 1.0
import org.kde.plasma.core 0.1 as PlasmaCore
import org.kde.qtextracomponents 0.1
Item {
id: smallIconsTabBox
property int screenWidth : 0
property int screenHeight : 0
property int imagePathPrefix: (new Date()).getTime()
width: Math.min(Math.max(screenWidth * 0.1, (icons.iconSize + icons.margins.left + icons.margins.right) * icons.count + background.margins.left + background.margins.bottom), screenWidth * 0.9)
height: Math.min(Math.max(screenHeight * 0.05, icons.iconSize + icons.margins.top + icons.margins.bottom + background.margins.top + background.margins.bottom), screenHeight * 0.5)
function setModel(model) {
icons.setModel(model);
}
function modelChanged() {
icons.modelChanged();
}
PlasmaCore.FrameSvgItem {
id: background
anchors.fill: parent
imagePath: "dialogs/background"
}
IconTabBox {
id: icons
iconSize: 16
anchors {
fill: parent
topMargin: background.margins.top
rightMargin: background.margins.right
bottomMargin: background.margins.bottom
leftMargin: background.margins.left
}
}
}

73
tabbox/qml/tabbox.qml Normal file
View file

@ -0,0 +1,73 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2011 Martin Gräßlin <mgraesslin@kde.org>
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/>.
*********************************************************************/
import QtQuick 1.0
Loader {
id: loader
property int screenWidth : 0
property int screenHeight : 0
property bool allDesktops: true
property string longestCaption: ""
onLoaded: {
if (item.screenWidth != undefined) {
item.screenWidth = screenWidth;
}
if (item.screenHeight != undefined) {
item.screenHeight = screenHeight;
}
if (item.allDesktops != undefined) {
item.allDesktops = allDesktops;
}
if (item.longestCaption != undefined) {
item.longestCaption = longestCaption;
}
if (item.setModel) {
item.setModel(clientModel);
}
}
onScreenWidthChanged: {
if (item && item.screenWidth != undefined) {
item.screenWidth = screenWidth;
}
}
onScreenHeightChanged: {
if (item && item.screenHeight != undefined) {
item.screenHeight = screenHeight;
}
}
onAllDesktopsChanged: {
if (item && item.allDesktops != undefined) {
item.allDesktops= allDesktops;
}
}
onLongestCaptionChanged: {
if (item && item.longestCaption != undefined) {
item.longestCaption = longestCaption;
}
}
Connections {
target: clientModel
onModelReset: {
if (item && item.modelChanged) {
item.modelChanged();
}
}
}
}

156
tabbox/qml/text.qml Normal file
View file

@ -0,0 +1,156 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2011 Martin Gräßlin <mgraesslin@kde.org>
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/>.
*********************************************************************/
import QtQuick 1.0
import org.kde.plasma.core 0.1 as PlasmaCore
import org.kde.qtextracomponents 0.1
Item {
id: textTabBox
property int screenWidth : 0
property int screenHeight : 0
property string longestCaption: ""
width: Math.min(Math.max(screenWidth * 0.2, textListView.maxRowWidth), screenWidth * 0.8)
height: Math.min(Math.max(screenHeight * 0.2, textListView.rowHeight * textListView.count + background.margins.top + background.margins.bottom), screenHeight * 0.8)
property int textMargin: 2
onLongestCaptionChanged: {
textListView.maxRowWidth = textListView.calculateMaxRowWidth();
}
function setModel(model) {
textListView.model = model;
textListView.maxRowWidth = textListView.calculateMaxRowWidth();
textListView.imageId++;
}
function modelChanged() {
textListView.imageId++;
}
PlasmaCore.Theme {
id: theme
}
// just to get the margin sizes
PlasmaCore.FrameSvgItem {
id: hoverItem
imagePath: "widgets/viewitem"
prefix: "hover"
visible: false
}
PlasmaCore.FrameSvgItem {
id: background
anchors.fill: parent
imagePath: "dialogs/background"
}
// delegate
Component {
id: listDelegate
Item {
id: delegateItem
width: textListView.width
height: textListView.rowHeight
Text {
id: captionItem
horizontalAlignment: Text.AlignHCenter
text: caption
color: theme.textColor
elide: Text.ElideMiddle
anchors {
left: parent.left
right: parent.right
top: parent.top
bottom: parent.bottom
topMargin: hoverItem.margins.top
rightMargin: hoverItem.margins.right
bottomMargin: hoverItem.margins.bottom
leftMargin: hoverItem.margins.left
}
}
}
}
ListView {
function calculateMaxRowWidth() {
var width = 0;
var textElement = Qt.createQmlObject(
'import Qt 4.7;'
+ 'Text {\n'
+ ' text: "' + textTabBox.longestCaption + '"\n'
+ ' visible: false\n'
+ '}',
textListView, "calculateMaxRowWidth");
width = Math.max(textElement.width, width);
textElement.destroy();
return width + hoverItem.margins.right + hoverItem.margins.left + background.margins.left + background.margins.right;
}
/**
* Calculates the height of one row based on the text height and icon size.
* @return Row height
**/
function calcRowHeight() {
var textElement = Qt.createQmlObject(
'import Qt 4.7;'
+ 'Text {\n'
+ ' text: "Some Text"\n'
+ ' visible: false\n'
+ '}',
textListView, "calcRowHeight");
var height = textElement.height;
textElement.destroy();
// icon size or two text elements and margins and hoverItem margins
return height + hoverItem.margins.top + hoverItem.margins.bottom;
}
/**
* Called from C++ to get the index at a mouse pos.
**/
function indexAtMousePos(pos) {
return textListView.indexAt(pos.x, pos.y);
}
id: textListView
objectName: "listView"
// the maximum text width + icon item width (32 + 4 margin) + margins for hover item + margins for background
property int maxRowWidth: calculateMaxRowWidth()
property int rowHeight: calcRowHeight()
// used for image provider URL to trick Qt into reloading icons when the model changes
property int imageId: 0
anchors {
fill: parent
topMargin: background.margins.top
leftMargin: background.margins.left
rightMargin: background.margins.right
bottomMargin: background.margins.bottom
}
clip: true
delegate: listDelegate
highlight: PlasmaCore.FrameSvgItem {
id: highlightItem
imagePath: "widgets/viewitem"
prefix: "hover"
width: textListView.width
}
MouseArea {
anchors.fill: parent
onClicked: textListView.currentIndex = textListView.indexAt(mouse.x, mouse.y)
}
}
}

View file

@ -23,6 +23,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// tabbox
#include "clientitemdelegate.h"
#include "clientmodel.h"
#include "declarative.h"
#include "desktopitemdelegate.h"
#include "desktopmodel.h"
#include "itemlayoutconfig.h"
@ -77,6 +78,7 @@ public:
// members
TabBoxConfig config;
TabBoxView* view;
DeclarativeView *m_declarativeView;
ClientModel* m_clientModel;
DesktopModel* m_desktopModel;
QModelIndex index;
@ -91,6 +93,7 @@ public:
TabBoxHandlerPrivate::TabBoxHandlerPrivate(TabBoxHandler *q)
: view(NULL)
, m_declarativeView(NULL)
{
this->q = q;
isShown = false;
@ -110,6 +113,7 @@ TabBoxHandlerPrivate::TabBoxHandlerPrivate(TabBoxHandler *q)
TabBoxHandlerPrivate::~TabBoxHandlerPrivate()
{
delete view;
delete m_declarativeView;
}
void TabBoxHandlerPrivate::createView()
@ -183,8 +187,14 @@ void TabBoxHandlerPrivate::updateHighlightWindows()
WId wId;
QVector< WId > data;
if (config.isShowTabBox() && view) {
wId = view->winId();
QWidget *w = NULL;
if (view && view->isVisible()) {
w = view;
} else if (m_declarativeView && m_declarativeView->isVisible()) {
w = m_declarativeView;
}
if (config.isShowTabBox() && w) {
wId = w->winId();
data.resize(2);
data[ 1 ] = wId;
} else {
@ -401,12 +411,21 @@ void TabBoxHandler::show()
d->updateOutline();
}
if (d->config.isShowTabBox()) {
if (d->config.tabBoxMode() == TabBoxConfig::ClientTabBox) {
// use declarative view
if (!d->m_declarativeView) {
d->m_declarativeView = new DeclarativeView(d->clientModel());
}
d->m_declarativeView->show();
d->m_declarativeView->setCurrentIndex(d->index);
} else {
if (!d->view) {
d->createView();
}
d->view->show();
d->view->updateGeometry();
}
}
if (d->config.isHighlightWindows()) {
d->updateHighlightWindows();
}
@ -424,6 +443,9 @@ void TabBoxHandler::hide(bool abort)
if (d->view) {
d->view->hide();
}
if (d->m_declarativeView) {
d->m_declarativeView->hide();
}
}
QModelIndex TabBoxHandler::nextPrev(bool forward) const
@ -512,6 +534,9 @@ void TabBoxHandler::setCurrentIndex(const QModelIndex& index)
if (d->view) {
d->view->setCurrentIndex(index);
}
if (d->m_declarativeView) {
d->m_declarativeView->setCurrentIndex(index);
}
d->index = index;
if (d->config.tabBoxMode() == TabBoxConfig::ClientTabBox) {
if (d->config.isShowOutline()) {
@ -574,20 +599,27 @@ QModelIndex TabBoxHandler::grabbedKeyEvent(QKeyEvent* event) const
bool TabBoxHandler::containsPos(const QPoint& pos) const
{
if (!d->view) {
QWidget *w = NULL;
if (d->view && d->view->isVisible()) {
w = d->view;
} else if (d->m_declarativeView && d->m_declarativeView->isVisible()) {
w = d->m_declarativeView;
} else {
return false;
}
return d->view->geometry().contains(pos);
return w->geometry().contains(pos);
}
QModelIndex TabBoxHandler::indexAt(const QPoint& pos) const
{
if (!d->view) {
return QModelIndex();
}
if (d->view && d->view->isVisible()) {
QPoint widgetPos = d->view->mapFromGlobal(pos);
QModelIndex ret = d->view->indexAt(widgetPos);
return ret;
return d->view->indexAt(widgetPos);
} else if (d->m_declarativeView && d->m_declarativeView->isVisible()) {
QPoint widgetPos = d->m_declarativeView->mapFromGlobal(pos);
return d->m_declarativeView->indexAt(widgetPos);
}
return QModelIndex();
}
QModelIndex TabBoxHandler::index(KWin::TabBox::TabBoxClient* client) const