1
0
mirror of https://github.com/KDE/latte-dock.git synced 2024-12-23 13:33:50 +03:00

provide latte internal widget explorer

This commit is contained in:
Michail Vourlakos 2021-01-16 19:12:42 +02:00
parent 3ec62e6ecc
commit 84d4d4cef7
13 changed files with 1061 additions and 6 deletions

View File

@ -45,6 +45,7 @@ void Package::initPackage(KPackage::Package *package)
package->setPath("org.kde.latte.shell");
package->addFileDefinition("defaults", QStringLiteral("defaults"), i18n("Latte Dock defaults"));
package->addFileDefinition("lattedockui", QStringLiteral("views/Panel.qml"), i18n("Latte Dock panel"));
package->addFileDefinition("widgetexplorerui", QStringLiteral("views/WidgetExplorer.qml"), i18n("Widget Explorer"));
//Configuration
package->addFileDefinition("lattedockconfigurationui", QStringLiteral("configuration/LatteDockConfiguration.qml"), i18n("Dock configuration UI"));
package->addFileDefinition("lattedocksecondaryconfigurationui", QStringLiteral("configuration/LatteDockSecondaryConfiguration.qml"), i18n("Dock secondary configuration UI"));

View File

@ -6,5 +6,6 @@ set(lattedock-app_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/secondaryconfigview.cpp
${CMAKE_CURRENT_SOURCE_DIR}/subconfigview.cpp
${CMAKE_CURRENT_SOURCE_DIR}/viewsettingsfactory.cpp
${CMAKE_CURRENT_SOURCE_DIR}/widgetexplorerview.cpp
PARENT_SCOPE
)

View File

@ -78,7 +78,7 @@ signals:
void enabledBordersChanged();
protected:
void syncSlideEffect();
virtual void syncSlideEffect();
virtual void init();
virtual void initParentView(Latte::View *view);
@ -87,7 +87,7 @@ protected:
void showEvent(QShowEvent *ev) override;
bool event(QEvent *e) override;
Qt::WindowFlags wFlags() const;
virtual Qt::WindowFlags wFlags() const;
protected:
bool m_isNormalWindow{true};

View File

@ -20,6 +20,7 @@
#include "viewsettingsfactory.h"
#include "primaryconfigview.h"
#include "widgetexplorerview.h"
#include "../view.h"
// Plasma
@ -81,5 +82,16 @@ ViewPart::PrimaryConfigView *ViewSettingsFactory::primaryConfigView(Latte::View
return m_primaryConfigView;
}
ViewPart::WidgetExplorerView *ViewSettingsFactory::widgetExplorerView(Latte::View *view)
{
if (!m_widgetExplorerView) {
m_widgetExplorerView = new ViewPart::WidgetExplorerView(view);
} else {
m_widgetExplorerView->setParentView(view);
}
return m_widgetExplorerView;
}
}

View File

@ -34,6 +34,7 @@ class View;
namespace ViewPart {
class PrimaryConfigView;
class WidgetExplorerView;
}
}
@ -55,9 +56,11 @@ public:
Plasma::Containment *lastContainment();
ViewPart::PrimaryConfigView *primaryConfigView(Latte::View *view);
ViewPart::WidgetExplorerView *widgetExplorerView(Latte::View *view);
private:
QPointer<ViewPart::PrimaryConfigView> m_primaryConfigView;
QPointer<ViewPart::WidgetExplorerView> m_widgetExplorerView;
QPointer<Plasma::Containment> m_lastContainment;
};

View File

@ -0,0 +1,287 @@
/*
* Copyright 2021 Michail Vourlakos <mvourlakos@gmail.com>
*
* This file is part of Latte-Dock
*
* Latte-Dock 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.
*
* Latte-Dock 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/>.
*/
#include "widgetexplorerview.h"
// local
#include "../panelshadows_p.h"
#include "../view.h"
#include "../../lattecorona.h"
#include "../../wm/abstractwindowinterface.h"
// Qt
#include <QQuickItem>
#include <QScreen>
// KDE
#include <KWindowEffects>
#include <KWindowSystem>
#include <KWayland/Client/plasmashell.h>
// Plasma
#include <Plasma/Package>
namespace Latte {
namespace ViewPart {
WidgetExplorerView::WidgetExplorerView(Latte::View *view)
: SubConfigView(view, QString("#widgetexplorerview#"), true)
{
setResizeMode(QQuickView::SizeRootObjectToView);
connect(this, &QQuickView::widthChanged, this, &WidgetExplorerView::updateEffects);
connect(this, &QQuickView::heightChanged, this, &WidgetExplorerView::updateEffects);
connect(this, &QQuickView::statusChanged, [&](QQuickView::Status status) {
if (status == QQuickView::Ready) {
updateEffects();
}
});
setParentView(view);
init();
}
void WidgetExplorerView::init()
{
SubConfigView::init();
QByteArray tempFilePath = "widgetexplorerui";
updateEnabledBorders();
auto source = QUrl::fromLocalFile(m_latteView->containment()->corona()->kPackage().filePath(tempFilePath));
setSource(source);
syncGeometry();
}
bool WidgetExplorerView::hideOnWindowDeactivate() const
{
return m_hideOnWindowDeactivate;
}
void WidgetExplorerView::setHideOnWindowDeactivate(bool hide)
{
if (m_hideOnWindowDeactivate == hide) {
return;
}
m_hideOnWindowDeactivate = hide;
emit hideOnWindowDeactivateChanged();
}
Qt::WindowFlags WidgetExplorerView::wFlags() const
{
return (flags() | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
}
QRect WidgetExplorerView::geometryWhenVisible() const
{
return m_geometryWhenVisible;
}
void WidgetExplorerView::initParentView(Latte::View *view)
{
SubConfigView::initParentView(view);
rootContext()->setContextProperty(QStringLiteral("containmentFromView"), m_latteView->containment());
updateEnabledBorders();
syncGeometry();
}
QRect WidgetExplorerView::availableScreenGeometry() const
{
int currentScrId = m_latteView->positioner()->currentScreenId();
QList<Latte::Types::Visibility> ignoreModes{Latte::Types::SidebarOnDemand,Latte::Types::SidebarAutoHide};
if (m_latteView->visibility() && m_latteView->visibility()->isSidebar()) {
ignoreModes.removeAll(Latte::Types::SidebarOnDemand);
ignoreModes.removeAll(Latte::Types::SidebarAutoHide);
}
QString activityid = m_latteView->layout()->lastUsedActivity();
return m_corona->availableScreenRectWithCriteria(currentScrId, activityid, ignoreModes, {}, false, true);
}
void WidgetExplorerView::syncGeometry()
{
if (!m_latteView || !m_latteView->layout() || !m_latteView->containment() || !rootObject()) {
return;
}
const QSize size(rootObject()->width(), rootObject()->height());
auto availGeometry = availableScreenGeometry();
int margin = availGeometry.height() == m_latteView->screenGeometry().height() ? 100 : 0;
auto geometry = QRect(availGeometry.x(), availGeometry.y(), size.width(), availGeometry.height()-margin);
updateEnabledBorders();
if (m_geometryWhenVisible == geometry) {
return;
}
m_geometryWhenVisible = geometry;
setPosition(geometry.topLeft());
if (m_shellSurface) {
m_shellSurface->setPosition(geometry.topLeft());
}
setMaximumSize(geometry.size());
setMinimumSize(geometry.size());
resize(geometry.size());
}
void WidgetExplorerView::showEvent(QShowEvent *ev)
{
if (m_shellSurface) {
//! under wayland it needs to be set again after its hiding
m_shellSurface->setPosition(m_geometryWhenVisible.topLeft());
}
SubConfigView::showEvent(ev);
if (!m_latteView) {
return;
}
syncGeometry();
requestActivate();
m_screenSyncTimer.start();
QTimer::singleShot(400, this, &WidgetExplorerView::syncGeometry);
emit showSignal();
}
void WidgetExplorerView::focusOutEvent(QFocusEvent *ev)
{
Q_UNUSED(ev);
if (!m_latteView) {
return;
}
hideConfigWindow();
}
void WidgetExplorerView::updateEffects()
{
//! Don't apply any effect before the wayland surface is created under wayland
//! https://bugs.kde.org/show_bug.cgi?id=392890
if (KWindowSystem::isPlatformWayland() && !m_shellSurface) {
return;
}
if (!m_background) {
m_background = new Plasma::FrameSvg(this);
}
if (m_background->imagePath() != "dialogs/background") {
m_background->setImagePath(QStringLiteral("dialogs/background"));
}
m_background->setEnabledBorders(m_enabledBorders);
m_background->resizeFrame(size());
QRegion mask = m_background->mask();
QRegion fixedMask = mask.isNull() ? QRegion(QRect(0,0,width(),height())) : mask;
if (!fixedMask.isEmpty()) {
setMask(fixedMask);
} else {
setMask(QRegion());
}
if (KWindowSystem::compositingActive()) {
KWindowEffects::enableBlurBehind(winId(), true, fixedMask);
} else {
KWindowEffects::enableBlurBehind(winId(), false);
}
}
void WidgetExplorerView::hideConfigWindow()
{
if (!m_hideOnWindowDeactivate) {
return;
}
if (m_shellSurface) {
//!NOTE: Avoid crash in wayland environment with qt5.9
close();
} else {
hide();
}
}
void WidgetExplorerView::syncSlideEffect()
{
if (!m_latteView || !m_latteView->containment()) {
return;
}
auto slideLocation = WindowSystem::AbstractWindowInterface::Slide::Left;
m_corona->wm()->slideWindow(*this, slideLocation);
}
//!BEGIN borders
void WidgetExplorerView::updateEnabledBorders()
{
if (!this->screen()) {
return;
}
Plasma::FrameSvg::EnabledBorders borders = Plasma::FrameSvg::AllBorders;
if (!m_geometryWhenVisible.isEmpty()) {
if (m_geometryWhenVisible.x() == m_latteView->screenGeometry().x()) {
borders &= ~Plasma::FrameSvg::LeftBorder;
}
if (m_geometryWhenVisible.y() == m_latteView->screenGeometry().y()) {
borders &= ~Plasma::FrameSvg::TopBorder;
}
if (m_geometryWhenVisible.height() == m_latteView->screenGeometry().height()) {
borders &= ~Plasma::FrameSvg::BottomBorder;
}
}
if (m_enabledBorders != borders) {
if (isVisible()) {
m_enabledBorders = borders;
}
m_corona->dialogShadows()->addWindow(this, m_enabledBorders);
emit enabledBordersChanged();
}
}
//!END borders
}
}

View File

@ -0,0 +1,105 @@
/*
* Copyright 2021 Michail Vourlakos <mvourlakos@gmail.com>
*
* This file is part of Latte-Dock
*
* Latte-Dock 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.
*
* Latte-Dock 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 WIDGETEXPLORERVIEW_H
#define WIDGETEXPLORERVIEW_H
// local
#include "subconfigview.h"
//Qt
#include <QObject>
#include <QQuickView>
#include <QPointer>
#include <QTimer>
// Plasma
#include <plasma/package.h>
#include <Plasma/FrameSvg>
namespace Plasma {
class Applet;
class Containment;
class FrameSvg;
class Types;
}
namespace KWayland {
namespace Client {
class PlasmaShellSurface;
}
}
namespace Latte {
class Corona;
class View;
}
namespace Latte {
namespace ViewPart {
class WidgetExplorerView : public SubConfigView
{
Q_OBJECT
Q_PROPERTY(bool hideOnWindowDeactivate READ hideOnWindowDeactivate WRITE setHideOnWindowDeactivate NOTIFY hideOnWindowDeactivateChanged)
public:
WidgetExplorerView(Latte::View *view);
bool hideOnWindowDeactivate() const;
void setHideOnWindowDeactivate(bool hide);
QRect geometryWhenVisible() const;
public slots:
Q_INVOKABLE void hideConfigWindow();
Q_INVOKABLE void syncGeometry() override;
Q_INVOKABLE void updateEffects();
signals:
void hideOnWindowDeactivateChanged();
void showSignal();
protected:
void showEvent(QShowEvent *ev) override;
void syncSlideEffect() override;
void focusOutEvent(QFocusEvent *ev) override;
void init() override;
void initParentView(Latte::View *view) override;
void updateEnabledBorders() override;
Qt::WindowFlags wFlags() const override;
private:
QRect availableScreenGeometry() const;
private:
bool m_hideOnWindowDeactivate{true};
QRect m_geometryWhenVisible;
//only for the mask on disabled compositing, not to actually paint
Plasma::FrameSvg *m_background{nullptr};
};
}
}
#endif //WIDGETEXPLORERVIEW_H

View File

@ -28,6 +28,7 @@
#include "settings/primaryconfigview.h"
#include "settings/secondaryconfigview.h"
#include "settings/viewsettingsfactory.h"
#include "settings/widgetexplorerview.h"
#include "../apptypes.h"
#include "../lattecorona.h"
#include "../data/layoutdata.h"
@ -178,6 +179,7 @@ View::View(Plasma::Corona *corona, QScreen *targetScreen, bool byPassWM)
}
connect(this->containment(), SIGNAL(statusChanged(Plasma::Types::ItemStatus)), SLOT(statusChanged(Plasma::Types::ItemStatus)));
connect(this->containment(), &Plasma::Containment::showAddWidgetsInterface, this, &View::showWidgetExplorer);
connect(this->containment(), &Plasma::Containment::userConfiguringChanged, this, [&]() {
emit inEditModeChanged();
});
@ -523,6 +525,16 @@ void View::showConfigurationInterface(Plasma::Applet *applet)
}
}
void View::showWidgetExplorer(const QPointF &point)
{
auto widgetExplorerView = m_corona->viewSettingsFactory()->widgetExplorerView(this);
if (!widgetExplorerView->isVisible()) {
// widgetExplorerView->syncSlideEffect();
widgetExplorerView->showAfter(400);
}
}
QRect View::localGeometry() const
{
return m_localGeometry;

View File

@ -279,6 +279,7 @@ public slots:
protected slots:
void showConfigurationInterface(Plasma::Applet *applet) override;
void showWidgetExplorer(const QPointF &point);
protected:
bool event(QEvent *ev) override;

View File

@ -88,14 +88,15 @@ void Menu::makeActions()
});
m_addWidgetsAction = new QAction(QIcon::fromTheme("list-add"), i18n("&Add Widgets..."), this);
m_addWidgetsAction->setStatusTip(i18n("Show Plasma Widget Explorer"));
connect(m_addWidgetsAction, &QAction::triggered, [ = ]() {
m_addWidgetsAction->setStatusTip(i18n("Show Widget Explorer"));
connect(m_addWidgetsAction, &QAction::triggered, this, &Menu::requestWidgetExplorer);
/*connect(m_addWidgetsAction, &QAction::triggered, [ = ]() {
QDBusInterface iface("org.kde.plasmashell", "/PlasmaShell", "", QDBusConnection::sessionBus());
if (iface.isValid()) {
iface.call("toggleWidgetExplorer");
}
});
});*/
m_configureAction = new QAction(QIcon::fromTheme("document-edit"), i18nc("view settings window", "View &Settings..."), this);
connect(m_configureAction, &QAction::triggered, this, &Menu::requestConfiguration);
@ -137,6 +138,12 @@ void Menu::requestConfiguration()
}
}
void Menu::requestWidgetExplorer()
{
if (this->containment()) {
emit this->containment()->showAddWidgetsInterface(QPointF());
}
}
QList<QAction *> Menu::contextualActions()
{

View File

@ -43,8 +43,9 @@ public:
private Q_SLOTS:
void makeActions();
void populateLayouts();
void requestConfiguration();
void quitApplication();
void requestConfiguration();
void requestWidgetExplorer();
void switchToLayout(QAction *action);

View File

@ -0,0 +1,236 @@
/*
* Copyright 2011 Marco Martin <mart@kde.org>
* Copyright 2015 Kai Uwe Broulik <kde@privat.broulik.de>
* Copyright 2021 Michail Vourlakos <mvourlakos@gmail.com>
*
* This program 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 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 Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import QtQuick 2.4
import QtQuick.Layouts 1.1
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.draganddrop 2.0
Item {
id: delegate
readonly property string pluginName: model.pluginName
readonly property bool pendingUninstall: pendingUninstallTimer.applets.indexOf(pluginName) > -1
width: list.cellWidth
height: list.cellHeight
DragArea {
anchors.fill: parent
supportedActions: Qt.MoveAction | Qt.LinkAction
//onDragStarted: tooltipDialog.visible = false
delegateImage: decoration
enabled: !delegate.pendingUninstall
mimeData {
source: parent
}
Component.onCompleted: mimeData.setData("text/x-plasmoidservicename", pluginName)
onDragStarted: {
kwindowsystem.showingDesktop = true;
main.draggingWidget = true;
}
onDrop: {
main.draggingWidget = false;
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onDoubleClicked: {
if (!delegate.pendingUninstall) {
widgetExplorer.addApplet(pluginName)
}
}
onEntered: delegate.GridView.view.currentIndex = index
onExited: delegate.GridView.view.currentIndex = - 1
}
ColumnLayout {
id: mainLayout
spacing: units.smallSpacing
anchors {
left: parent.left
right: parent.right
//bottom: parent.bottom
margins: units.smallSpacing * 2
rightMargin: units.smallSpacing * 2 // don't cram the text to the border too much
top: parent.top
}
Item {
id: iconContainer
width: units.iconSizes.enormous
height: width
Layout.alignment: Qt.AlignHCenter
opacity: delegate.pendingUninstall ? 0.6 : 1
Behavior on opacity {
OpacityAnimator {
duration: units.longDuration
easing.type: Easing.InOutQuad
}
}
Item {
id: iconWidget
anchors.fill: parent
PlasmaCore.IconItem {
anchors.fill: parent
source: model.decoration
visible: model.screenshot === ""
}
Image {
width: units.iconSizes.enormous
height: width
anchors.fill: parent
fillMode: Image.PreserveAspectFit
source: model.screenshot
}
}
Item {
id: badgeMask
anchors.fill: parent
Rectangle {
x: Math.round(-units.smallSpacing * 1.5 / 2)
y: x
width: runningBadge.width + Math.round(units.smallSpacing * 1.5)
height: width
radius: height
visible: running && delegate.GridView.isCurrentItem
}
}
Rectangle {
id: runningBadge
width: height
height: Math.round(theme.mSize(countLabel.font).height * 1.3)
radius: height
color: theme.highlightColor
visible: running && delegate.GridView.isCurrentItem
onVisibleChanged: maskShaderSource.scheduleUpdate()
PlasmaComponents.Label {
id: countLabel
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: running
}
}
ShaderEffect {
anchors.fill: parent
property var source: ShaderEffectSource {
sourceItem: iconWidget
hideSource: true
live: false
}
property var mask: ShaderEffectSource {
id: maskShaderSource
sourceItem: badgeMask
hideSource: true
live: false
}
supportsAtlasTextures: true
fragmentShader: "
varying highp vec2 qt_TexCoord0;
uniform highp float qt_Opacity;
uniform lowp sampler2D source;
uniform lowp sampler2D mask;
void main() {
gl_FragColor = texture2D(source, qt_TexCoord0.st) * (1.0 - (texture2D(mask, qt_TexCoord0.st).a)) * qt_Opacity;
}
"
}
PlasmaComponents.ToolButton {
id: uninstallButton
anchors {
top: parent.top
right: parent.right
}
iconSource: delegate.pendingUninstall ? "edit-undo" : "edit-delete"
// we don't really "undo" anything but we'll pretend to the user that we do
tooltip: delegate.pendingUninstall ? i18nd("plasma_shell_org.kde.plasma.desktop", "Undo uninstall")
: i18nd("plasma_shell_org.kde.plasma.desktop", "Uninstall widget")
flat: false
visible: model.local && delegate.GridView.isCurrentItem
onHoveredChanged: {
if (hovered) {
// hovering the uninstall button triggers onExited of the main mousearea
delegate.GridView.view.currentIndex = index
}
}
onClicked: {
var pending = installTimer.applets
if (delegate.pendingUninstall) {
var index = pending.indexOf(pluginName)
if (index > -1) {
pending.splice(index, 1)
}
} else {
pending.push(pluginName)
}
pendingUninstallTimer.applets = pending
if (pending.length) {
pendingUninstallTimer.restart()
} else {
pendingUninstallTimer.stop()
}
}
}
}
PlasmaExtras.Heading {
id: heading
Layout.fillWidth: true
level: 4
text: model.name
elide: Text.ElideRight
wrapMode: Text.WordWrap
maximumLineCount: 2
lineHeight: 0.95
horizontalAlignment: Text.AlignHCenter
}
PlasmaComponents.Label {
Layout.fillWidth: true
// otherwise causes binding loop due to the way the Plasma sets the height
height: implicitHeight
text: model.description
font: theme.smallestFont
wrapMode: Text.WordWrap
elide: Text.ElideRight
maximumLineCount: heading.lineCount === 1 ? 3 : 2
horizontalAlignment: Text.AlignHCenter
}
}
}
}

View File

@ -0,0 +1,389 @@
/*
* Copyright 2011 Marco Martin <mart@kde.org>
* Copyright 2021 Michail Vourlakos <mvourlakos@gmail.com>
*
* This program 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 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 Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import QtQuick 2.7
import QtQuick.Controls 2.5 as QQC2
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.kquickcontrolsaddons 2.0
import org.kde.kwindowsystem 1.0
import QtQuick.Window 2.1
import QtQuick.Layouts 1.1
import org.kde.plasma.private.shell 2.0 as PlasmaShell
Item {
id: main
width: Math.max(heading.paintedWidth, units.iconSizes.enormous * 3 + units.smallSpacing * 4 + units.gridUnit * 2)
// height: 800//Screen.height
opacity: draggingWidget ? 0.3 : 1
//property QtObject containment
//external drop events can cause a raise event causing us to lose focus and
//therefore get deleted whilst we are still in a drag exec()
//this is a clue to the owning dialog that hideOnWindowDeactivate should be deleted
//See https://bugs.kde.org/show_bug.cgi?id=332733
property bool preventWindowHide: draggingWidget
|| categoriesDialog.status !== PlasmaComponents.DialogStatus.Closed
|| getWidgetsDialog.status !== PlasmaComponents.DialogStatus.Closed
property bool outputOnly: draggingWidget
property Item categoryButton
property bool draggingWidget: false
signal closed();
onClosed: {
if (main.preventWindowHide) {
return;
}
viewConfig.hideConfigWindow();
}
onVisibleChanged: {
if (!visible) {
kwindowsystem.showingDesktop = false
}
}
Component.onDestruction: {
if (pendingUninstallTimer.running) {
// we're not being destroyed so at least reset the filters
widgetExplorer.widgetsModel.filterQuery = ""
widgetExplorer.widgetsModel.filterType = ""
widgetExplorer.widgetsModel.searchTerm = ""
}
}
function addCurrentApplet() {
var pluginName = list.currentItem ? list.currentItem.pluginName : ""
if (pluginName) {
widgetExplorer.addApplet(pluginName)
}
}
KWindowSystem {
id: kwindowsystem
}
QQC2.Action {
shortcut: "Escape"
onTriggered: {
if (searchInput.length > 0) {
searchInput.text = ""
} else {
main.closed();
}
}
}
QQC2.Action {
shortcut: "Up"
onTriggered: list.currentIndex = (list.count + list.currentIndex - 1) % list.count
}
QQC2.Action {
shortcut: "Down"
onTriggered: list.currentIndex = (list.currentIndex + 1) % list.count
}
QQC2.Action {
shortcut: "Enter"
onTriggered: addCurrentApplet()
}
QQC2.Action {
shortcut: "Return"
onTriggered: addCurrentApplet()
}
PlasmaCore.FrameSvgItem{
id: backgroundFrameSvgItem
anchors.fill: parent
imagePath: "dialogs/background"
enabledBorders: viewConfig.enabledBorders
onEnabledBordersChanged: viewConfig.updateEffects()
Component.onCompleted: viewConfig.updateEffects()
}
PlasmaShell.WidgetExplorer {
id:widgetExplorer
//view: desktop
containment: containmentFromView
onShouldClose: main.closed();
}
PlasmaComponents.ModelContextMenu {
id: categoriesDialog
visualParent: categoryButton
// model set on first invocation
onClicked: {
list.contentX = 0
list.contentY = 0
categoryButton.text = (model.filterData ? model.display : i18nd("plasma_shell_org.kde.plasma.desktop", "All Widgets"))
widgetExplorer.widgetsModel.filterQuery = model.filterData
widgetExplorer.widgetsModel.filterType = model.filterType
}
}
PlasmaComponents.ModelContextMenu {
id: getWidgetsDialog
visualParent: getWidgetsButton
placement: PlasmaCore.Types.TopPosedLeftAlignedPopup
// model set on first invocation
onClicked: model.trigger()
}
/*
PlasmaCore.Dialog {
id: tooltipDialog
property Item appletDelegate
location: PlasmaCore.Types.RightEdge //actually we want this to be the opposite location of the explorer itself
type: PlasmaCore.Dialog.Tooltip
flags:Qt.Window|Qt.WindowStaysOnTopHint|Qt.X11BypassWindowManagerHint
onAppletDelegateChanged: {
if (!appletDelegate) {
toolTipHideTimer.restart()
toolTipShowTimer.running = false
} else if (tooltipDialog.visible) {
tooltipDialog.visualParent = appletDelegate
} else {
tooltipDialog.visualParent = appletDelegate
toolTipShowTimer.restart()
toolTipHideTimer.running = false
}
}
mainItem: Tooltip { id: tooltipWidget }
Behavior on y {
NumberAnimation { duration: units.longDuration }
}
}
Timer {
id: toolTipShowTimer
interval: 500
repeat: false
onTriggered: {
tooltipDialog.visible = true
}
}
Timer {
id: toolTipHideTimer
interval: 1000
repeat: false
onTriggered: tooltipDialog.visible = false
}
*/
PlasmaExtras.PlasmoidHeading {
id: topArea
implicitWidth: header.implicitWidth
implicitHeight: header.implicitHeight
anchors {
top: parent.top
left: parent.left
right: parent.right
}
ColumnLayout {
id: header
anchors.fill: parent
RowLayout {
PlasmaExtras.Heading {
id: heading
level: 1
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Widgets")
elide: Text.ElideRight
Layout.fillWidth: true
}
PlasmaComponents.ToolButton {
id: getWidgetsButton
iconSource: "get-hot-new-stuff"
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Get New Widgets...")
onClicked: {
getWidgetsDialog.model = widgetExplorer.widgetsMenuActions
getWidgetsDialog.openRelative()
}
}
PlasmaComponents.ToolButton {
id: closeButton
iconSource: "window-close"
onClicked: main.closed()
}
}
RowLayout {
PlasmaComponents.TextField {
id: searchInput
Layout.fillWidth: true
clearButtonShown: true
placeholderText: i18nd("plasma_shell_org.kde.plasma.desktop", "Search...")
onTextChanged: {
list.positionViewAtBeginning()
list.currentIndex = -1
widgetExplorer.widgetsModel.searchTerm = text
}
Component.onCompleted: forceActiveFocus()
}
PlasmaComponents.ToolButton {
id: categoryButton
tooltip: i18nd("plasma_shell_org.kde.plasma.desktop", "Categories")
text: i18nd("plasma_shell_org.kde.plasma.desktop", "All Widgets")
iconSource: "view-filter"
onClicked: {
categoriesDialog.model = widgetExplorer.filterModel
categoriesDialog.open(0, categoryButton.height)
}
}
}
Item {
height: units.smallSpacing
}
}
}
Timer {
id: setModelTimer
interval: 20
running: true
onTriggered: list.model = widgetExplorer.widgetsModel
}
PlasmaExtras.ScrollArea {
anchors {
top: topArea.bottom
left: parent.left
right: parent.right
bottom: parent.bottom
}
verticalScrollBarPolicy: Qt.ScrollBarAlwaysOn
// hide the flickering by fading in nicely
opacity: setModelTimer.running ? 0 : 1
Behavior on opacity {
OpacityAnimator {
duration: units.longDuration
easing.type: Easing.InOutQuad
}
}
GridView {
id: list
// model set delayed by Timer above
activeFocusOnTab: true
keyNavigationWraps: true
cellWidth: Math.floor((width - units.smallSpacing) / 3)
cellHeight: cellWidth + units.gridUnit * 4 + units.smallSpacing * 2
delegate: AppletDelegate {}
highlight: PlasmaComponents.Highlight {}
highlightMoveDuration: 0
//highlightResizeDuration: 0
//slide in to view from the left
add: Transition {
NumberAnimation {
properties: "x"
from: -list.width
duration: units.shortDuration
}
}
//slide out of view to the right
remove: Transition {
NumberAnimation {
properties: "x"
to: list.width
duration: units.shortDuration
}
}
//if we are adding other items into the view use the same animation as normal adding
//this makes everything slide in together
//if we make it move everything ends up weird
addDisplaced: list.add
//moved due to filtering
displaced: Transition {
NumberAnimation {
properties: "x,y"
duration: units.shortDuration
}
}
PlasmaExtras.Heading {
anchors.fill: parent
anchors.margins: units.largeSpacing
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
wrapMode: Text.WordWrap
level: 2
text: searchInput.text.length > 0 ? i18n("No widgets matched the search terms") : i18n("No widgets available")
enabled: false
visible: list.count == 0
}
}
}
//! Bindings
Binding{
target: viewConfig
property: "hideOnWindowDeactivate"
value: !main.preventWindowHide
}
//! Timers
Timer {
id: pendingUninstallTimer
// keeps track of the applets the user wants to uninstall
property var applets: []
interval: 60000 // one minute
onTriggered: {
for (var i = 0, length = applets.length; i < length; ++i) {
widgetExplorer.uninstall(applets[i])
}
applets = []
/*if (sidePanelStack.state !== "widgetExplorer" && widgetExplorer) {
widgetExplorer.destroy()
widgetExplorer = null
}*/
}
}
}