From e1cbb336316a4a776f85c09c04e090ff94681773 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Sat, 14 Jan 2012 11:24:42 +0100 Subject: [PATCH] Desktop Box support for QML based TabBox First very simple layout just rendering icon and name. Good enough for the start. --- CMakeLists.txt | 1 + tabbox/declarative.cpp | 30 +++++-- tabbox/declarative.h | 4 +- tabbox/qml/desktop.qml | 174 +++++++++++++++++++++++++++++++++++++++ tabbox/tabboxhandler.cpp | 22 +++-- 5 files changed, 220 insertions(+), 11 deletions(-) create mode 100644 tabbox/qml/desktop.qml diff --git a/CMakeLists.txt b/CMakeLists.txt index 1fb4d76c5e..7495c397a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -246,6 +246,7 @@ install( FILES tabbox/qml/informative.qml tabbox/qml/big_icons.qml tabbox/qml/compact.qml + tabbox/qml/desktop.qml tabbox/qml/small_icons.qml tabbox/qml/tabbox.qml tabbox/qml/text.qml diff --git a/tabbox/declarative.cpp b/tabbox/declarative.cpp index 81103cc687..0131bb9d76 100644 --- a/tabbox/declarative.cpp +++ b/tabbox/declarative.cpp @@ -101,9 +101,10 @@ QPixmap ImageProvider::requestPixmap(const QString &id, QSize *size, const QSize return icon; } -DeclarativeView::DeclarativeView(QAbstractItemModel *model, QWidget *parent) +DeclarativeView::DeclarativeView(QAbstractItemModel *model, TabBoxConfig::TabBoxMode mode, QWidget *parent) : QDeclarativeView(parent) , m_model(model) + , m_mode(mode) , m_currentScreenGeometry() , m_frame(new Plasma::FrameSvg(this)) , m_currentLayout() @@ -130,7 +131,11 @@ DeclarativeView::DeclarativeView(QAbstractItemModel *model, QWidget *parent) kdeclarative.setupBindings(); qmlRegisterType("org.kde.kwin", 0, 1, "ThumbnailItem"); rootContext()->setContextProperty("viewId", static_cast(winId())); - rootContext()->setContextProperty("clientModel", model); + if (m_mode == TabBoxConfig::ClientTabBox) { + rootContext()->setContextProperty("clientModel", model); + } else if (m_mode == TabBoxConfig::DesktopTabBox) { + rootContext()->setContextProperty("clientModel", model); + } setSource(QUrl(KStandardDirs::locate("data", "kwin/tabbox/tabbox.qml"))); // FrameSvg @@ -139,7 +144,9 @@ DeclarativeView::DeclarativeView(QAbstractItemModel *model, QWidget *parent) m_frame->setEnabledBorders(Plasma::FrameSvg::AllBorders); connect(tabBox, SIGNAL(configChanged()), SLOT(updateQmlSource())); - connect(tabBox, SIGNAL(embeddedChanged(bool)), SLOT(slotEmbeddedChanged(bool))); + if (m_mode == TabBoxConfig::ClientTabBox) { + connect(tabBox, SIGNAL(embeddedChanged(bool)), SLOT(slotEmbeddedChanged(bool))); + } } void DeclarativeView::showEvent(QShowEvent *event) @@ -154,7 +161,9 @@ void DeclarativeView::showEvent(QShowEvent *event) rootObject()->setProperty("allDesktops", tabBox->config().tabBoxMode() == TabBoxConfig::ClientTabBox && ((tabBox->config().clientListMode() == TabBoxConfig::AllDesktopsClientList) || (tabBox->config().clientListMode() == TabBoxConfig::AllDesktopsApplicationList))); - rootObject()->setProperty("longestCaption", static_cast(m_model)->longestCaption()); + if (ClientModel *clientModel = qobject_cast(m_model)) { + rootObject()->setProperty("longestCaption", clientModel->longestCaption()); + } if (QObject *item = rootObject()->findChild("listView")) { item->setProperty("currentIndex", tabBox->first().row()); @@ -254,6 +263,9 @@ void DeclarativeView::slotUpdateGeometry() void DeclarativeView::setCurrentIndex(const QModelIndex &index) { + if (tabBox->config().tabBoxMode() != m_mode) { + return; + } if (QObject *item = rootObject()->findChild("listView")) { item->setProperty("currentIndex", index.row()); } @@ -281,14 +293,22 @@ void DeclarativeView::currentIndexChanged(int row) void DeclarativeView::updateQmlSource(bool force) { + if (tabBox->config().tabBoxMode() != m_mode) { + return; + } if (!force && tabBox->config().layoutName() == m_currentLayout) { return; } m_currentLayout = tabBox->config().layoutName(); QString file = KStandardDirs::locate("data", "kwin/tabbox/" + m_currentLayout.toLower().replace(' ', '_') + ".qml"); + if (m_mode == TabBoxConfig::DesktopTabBox) { + file = KStandardDirs::locate("data", "kwin/tabbox/desktop.qml"); + } if (file.isNull()) { // fallback to default - file = KStandardDirs::locate("data", "kwin/tabbox/informative.qml"); + if (m_mode == TabBoxConfig::ClientTabBox) { + file = KStandardDirs::locate("data", "kwin/tabbox/informative.qml"); + } } rootObject()->setProperty("source", QUrl(file)); } diff --git a/tabbox/declarative.h b/tabbox/declarative.h index 104e6cf79d..9bdad158a2 100644 --- a/tabbox/declarative.h +++ b/tabbox/declarative.h @@ -22,6 +22,7 @@ along with this program. If not, see . // includes #include #include +#include "tabboxconfig.h" // forward declaration class QAbstractItemModel; @@ -52,7 +53,7 @@ class DeclarativeView : public QDeclarativeView { Q_OBJECT public: - DeclarativeView(QAbstractItemModel *model, QWidget *parent = NULL); + DeclarativeView(QAbstractItemModel *model, TabBoxConfig::TabBoxMode mode, QWidget *parent = NULL); virtual void showEvent(QShowEvent *event); virtual void resizeEvent(QResizeEvent *event); void setCurrentIndex(const QModelIndex &index); @@ -71,6 +72,7 @@ private Q_SLOTS: void slotWindowChanged(WId wId, unsigned int properties); private: QAbstractItemModel *m_model; + TabBoxConfig::TabBoxMode m_mode; QRect m_currentScreenGeometry; /** * Background Frame required for setting the blur mask diff --git a/tabbox/qml/desktop.qml b/tabbox/qml/desktop.qml new file mode 100644 index 0000000000..f63996cc66 --- /dev/null +++ b/tabbox/qml/desktop.qml @@ -0,0 +1,174 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2012 Martin Gräßlin + +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 . +*********************************************************************/ +import QtQuick 1.0 +import org.kde.plasma.core 0.1 as PlasmaCore +import org.kde.qtextracomponents 0.1 + +Item { + id: desktopTabBox + property int screenWidth : 0 + property int screenHeight : 0 + property bool allDesktops: true + property string longestCaption: "" + property int optimalWidth: listView.maxRowWidth + property int optimalHeight: listView.rowHeight * listView.count + background.margins.top + background.margins.bottom + property bool canStretchX: true + property bool canStretchY: false + width: Math.min(Math.max(screenWidth * 0.2, optimalWidth), screenWidth * 0.8) + height: Math.min(optimalHeight, screenHeight * 0.8) + + property int textMargin: 2 + + onLongestCaptionChanged: { + listView.maxRowWidth = listView.calculateMaxRowWidth(); + } + + function setModel(model) { + listView.model = model; + listView.maxRowWidth = listView.calculateMaxRowWidth(); + } + + 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 + QIconItem { + id: iconElement + icon: "user-desktop" + width: 32 + height: 32 + anchors { + topMargin: (listView.rowHeight - 32) / 2 + left: parent.left + top: parent.top + leftMargin: hoverItem.margins.left + } + } + Text { + id: captionItem + horizontalAlignment: Text.AlignHCenter + text: display + font.bold: true + color: theme.textColor + elide: Text.ElideMiddle + anchors { + left: iconElement.right + right: parent.right + top: parent.top + topMargin: desktopTabBox.textMargin + hoverItem.margins.top + rightMargin: hoverItem.margins.right + leftMargin: desktopTabBox.textMargin + } + } + MouseArea { + anchors.fill: parent + onClicked: { + listView.currentIndex = index; + listView.currentIndexChanged(listView.currentIndex); + } + } + } + } + ListView { + function calculateMaxRowWidth() { + var width = 0; + var textElement = Qt.createQmlObject( + 'import Qt 4.7;' + + 'Text {\n' + + ' text: "' + desktopTabBox.longestCaption + '"\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 + desktopTabBox.textMargin * 2 + 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); + } + signal currentIndexChanged(int index) + 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 + } + highlightMoveDuration: 250 + } +} diff --git a/tabbox/tabboxhandler.cpp b/tabbox/tabboxhandler.cpp index 00c0343f0b..dfcc0b5894 100644 --- a/tabbox/tabboxhandler.cpp +++ b/tabbox/tabboxhandler.cpp @@ -79,6 +79,7 @@ public: TabBoxConfig config; TabBoxView* view; DeclarativeView *m_declarativeView; + DeclarativeView *m_declarativeDesktopView; ClientModel* m_clientModel; DesktopModel* m_desktopModel; QModelIndex index; @@ -98,6 +99,7 @@ public: TabBoxHandlerPrivate::TabBoxHandlerPrivate(TabBoxHandler *q) : view(NULL) , m_declarativeView(NULL) + , m_declarativeDesktopView(NULL) , m_embedded(0) , m_embeddedOffset(QPoint(0, 0)) , m_embeddedSize(QSize(0, 0)) @@ -121,6 +123,7 @@ TabBoxHandlerPrivate::~TabBoxHandlerPrivate() { delete view; delete m_declarativeView; + delete m_declarativeDesktopView; } void TabBoxHandlerPrivate::createView() @@ -421,16 +424,16 @@ void TabBoxHandler::show() if (d->config.tabBoxMode() == TabBoxConfig::ClientTabBox) { // use declarative view if (!d->m_declarativeView) { - d->m_declarativeView = new DeclarativeView(d->clientModel()); + d->m_declarativeView = new DeclarativeView(d->clientModel(), TabBoxConfig::ClientTabBox); } d->m_declarativeView->show(); d->m_declarativeView->setCurrentIndex(d->index); } else { - if (!d->view) { - d->createView(); + if (!d->m_declarativeDesktopView) { + d->m_declarativeDesktopView = new DeclarativeView(d->desktopModel(), TabBoxConfig::DesktopTabBox); } - d->view->show(); - d->view->updateGeometry(); + d->m_declarativeDesktopView->show(); + d->m_declarativeDesktopView->setCurrentIndex(d->index); } } if (d->config.isHighlightWindows()) { @@ -453,6 +456,9 @@ void TabBoxHandler::hide(bool abort) if (d->m_declarativeView) { d->m_declarativeView->hide(); } + if (d->m_declarativeDesktopView) { + d->m_declarativeDesktopView->hide(); + } } QModelIndex TabBoxHandler::nextPrev(bool forward) const @@ -550,6 +556,9 @@ void TabBoxHandler::setCurrentIndex(const QModelIndex& index) if (d->m_declarativeView) { d->m_declarativeView->setCurrentIndex(index); } + if (d->m_declarativeDesktopView) { + d->m_declarativeDesktopView->setCurrentIndex(index); + } d->index = index; if (d->config.tabBoxMode() == TabBoxConfig::ClientTabBox) { if (d->config.isShowOutline()) { @@ -639,6 +648,9 @@ QModelIndex TabBoxHandler::indexAt(const QPoint& pos) const } else if (d->m_declarativeView && d->m_declarativeView->isVisible()) { QPoint widgetPos = d->m_declarativeView->mapFromGlobal(pos); return d->m_declarativeView->indexAt(widgetPos); + } else if (d->m_declarativeDesktopView && d->m_declarativeDesktopView->isVisible()) { + QPoint widgetPos = d->m_declarativeDesktopView->mapFromGlobal(pos); + return d->m_declarativeDesktopView->indexAt(widgetPos); } return QModelIndex(); }