diff --git a/app/view/containmentinterface.cpp b/app/view/containmentinterface.cpp index 4239183c..a4c49227 100644 --- a/app/view/containmentinterface.cpp +++ b/app/view/containmentinterface.cpp @@ -1,635 +1,639 @@ /* * Copyright 2019 Michail Vourlakos * * 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 . */ #include "containmentinterface.h" // local #include "view.h" #include "../lattecorona.h" #include "../layout/genericlayout.h" #include "../settings/universalsettings.h" // Qt #include // Plasma #include #include #include // KDE #include #include namespace Latte { namespace ViewPart { ContainmentInterface::ContainmentInterface(Latte::View *parent) : QObject(parent), m_view(parent) { m_corona = qobject_cast(m_view->corona()); m_latteTasksModel = new TasksModel(this); m_plasmaTasksModel = new TasksModel(this); m_appletsExpandedConnectionsTimer.setInterval(2000); m_appletsExpandedConnectionsTimer.setSingleShot(true); connect(&m_appletsExpandedConnectionsTimer, &QTimer::timeout, this, &ContainmentInterface::updateAppletsTracking); connect(m_view, &View::containmentChanged , this, [&]() { if (m_view->containment()) { connect(m_view->containment(), &Plasma::Containment::appletAdded, this, &ContainmentInterface::on_appletAdded); m_appletsExpandedConnectionsTimer.start(); } }); connect(m_latteTasksModel, &TasksModel::countChanged, this, &ContainmentInterface::onLatteTasksCountChanged); connect(m_plasmaTasksModel, &TasksModel::countChanged, this, &ContainmentInterface::onPlasmaTasksCountChanged); } ContainmentInterface::~ContainmentInterface() { } -void ContainmentInterface::identifyMainItem() +void ContainmentInterface::identifyShortcutsHost() { - if (m_mainItem) { + if (m_shortcutsHost) { return; } if (QQuickItem *graphicItem = m_view->containment()->property("_plasma_graphicObject").value()) { const auto &childItems = graphicItem->childItems(); for (QQuickItem *item : childItems) { if (item->objectName() == "containmentViewLayout" ) { - m_mainItem = item; - identifyMethods(); - return; + for (QQuickItem *subitem : item->childItems()) { + if (subitem->objectName() == "PositionShortcutsAbilityHost") { + m_shortcutsHost = subitem; + identifyMethods(); + return; + } + } } } } } void ContainmentInterface::identifyMethods() { - int aeIndex = m_mainItem->metaObject()->indexOfMethod("activateEntryAtIndex(QVariant)"); - int niIndex = m_mainItem->metaObject()->indexOfMethod("newInstanceForEntryAtIndex(QVariant)"); - int sbIndex = m_mainItem->metaObject()->indexOfMethod("setShowAppletShortcutBadges(QVariant,QVariant,QVariant,QVariant)"); - int afiIndex = m_mainItem->metaObject()->indexOfMethod("appletIdForIndex(QVariant)"); + int aeIndex = m_shortcutsHost->metaObject()->indexOfMethod("activateEntryAtIndex(QVariant)"); + int niIndex = m_shortcutsHost->metaObject()->indexOfMethod("newInstanceForEntryAtIndex(QVariant)"); + int sbIndex = m_shortcutsHost->metaObject()->indexOfMethod("setShowAppletShortcutBadges(QVariant,QVariant,QVariant,QVariant)"); + int afiIndex = m_shortcutsHost->metaObject()->indexOfMethod("appletIdForIndex(QVariant)"); - m_activateEntryMethod = m_mainItem->metaObject()->method(aeIndex); - m_appletIdForIndexMethod = m_mainItem->metaObject()->method(afiIndex); - m_newInstanceMethod = m_mainItem->metaObject()->method(niIndex); - m_showShortcutsMethod = m_mainItem->metaObject()->method(sbIndex); + m_activateEntryMethod = m_shortcutsHost->metaObject()->method(aeIndex); + m_appletIdForIndexMethod = m_shortcutsHost->metaObject()->method(afiIndex); + m_newInstanceMethod = m_shortcutsHost->metaObject()->method(niIndex); + m_showShortcutsMethod = m_shortcutsHost->metaObject()->method(sbIndex); } bool ContainmentInterface::applicationLauncherHasGlobalShortcut() const { if (!containsApplicationLauncher()) { return false; } uint launcherAppletId = applicationLauncherId(); const auto applets = m_view->containment()->applets(); for (auto applet : applets) { if (applet->id() == launcherAppletId) { return !applet->globalShortcut().isEmpty(); } } return false; } bool ContainmentInterface::applicationLauncherInPopup() const { if (!containsApplicationLauncher()) { return false; } uint launcherAppletId = applicationLauncherId(); QString launcherPluginId; const auto applets = m_view->containment()->applets(); for (auto applet : applets) { if (applet->id() == launcherAppletId) { launcherPluginId = applet->kPackage().metadata().pluginId(); } } return launcherPluginId != "org.kde.plasma.kickerdash"; } bool ContainmentInterface::containsApplicationLauncher() const { return (applicationLauncherId() >= 0); } bool ContainmentInterface::isCapableToShowShortcutBadges() { - identifyMainItem(); + identifyShortcutsHost(); if (!hasLatteTasks() && hasPlasmaTasks()) { return false; } return m_showShortcutsMethod.isValid(); } int ContainmentInterface::applicationLauncherId() const { const auto applets = m_view->containment()->applets(); auto launcherId{-1}; for (auto applet : applets) { const auto provides = applet->kPackage().metadata().value(QStringLiteral("X-Plasma-Provides")); if (provides.contains(QLatin1String("org.kde.plasma.launchermenu"))) { if (!applet->globalShortcut().isEmpty()) { return applet->id(); } else if (launcherId == -1) { launcherId = applet->id(); } } } return launcherId; } bool ContainmentInterface::updateBadgeForLatteTask(const QString identifier, const QString value) { if (!hasLatteTasks()) { return false; } const auto &applets = m_view->containment()->applets(); for (auto *applet : applets) { KPluginMetaData meta = applet->kPackage().metadata(); if (meta.pluginId() == "org.kde.latte.plasmoid") { if (QQuickItem *appletInterface = applet->property("_plasma_graphicObject").value()) { const auto &childItems = appletInterface->childItems(); if (childItems.isEmpty()) { continue; } for (QQuickItem *item : childItems) { if (auto *metaObject = item->metaObject()) { // not using QMetaObject::invokeMethod to avoid warnings when calling // this on applets that don't have it or other child items since this // is pretty much trial and error. // Also, "var" arguments are treated as QVariant in QMetaObject int methodIndex = metaObject->indexOfMethod("updateBadge(QVariant,QVariant)"); if (methodIndex == -1) { continue; } QMetaMethod method = metaObject->method(methodIndex); if (method.invoke(item, Q_ARG(QVariant, identifier), Q_ARG(QVariant, value))) { return true; } } } } } } return false; } bool ContainmentInterface::activatePlasmaTask(const int index) { bool containsPlasmaTaskManager{hasPlasmaTasks() && !hasLatteTasks()}; if (!containsPlasmaTaskManager) { return false; } const auto &applets = m_view->containment()->applets(); for (auto *applet : applets) { const auto &provides = KPluginMetaData::readStringList(applet->pluginMetaData().rawData(), QStringLiteral("X-Plasma-Provides")); if (provides.contains(QLatin1String("org.kde.plasma.multitasking"))) { if (QQuickItem *appletInterface = applet->property("_plasma_graphicObject").value()) { const auto &childItems = appletInterface->childItems(); if (childItems.isEmpty()) { continue; } KPluginMetaData meta = applet->kPackage().metadata(); for (QQuickItem *item : childItems) { if (auto *metaObject = item->metaObject()) { int methodIndex{metaObject->indexOfMethod("activateTaskAtIndex(QVariant)")}; if (methodIndex == -1) { continue; } QMetaMethod method = metaObject->method(methodIndex); if (method.invoke(item, Q_ARG(QVariant, index - 1))) { showShortcutBadges(false, true); return true; } } } } } } return false; } bool ContainmentInterface::newInstanceForPlasmaTask(const int index) { bool containsPlasmaTaskManager{hasPlasmaTasks() && !hasLatteTasks()}; if (!containsPlasmaTaskManager) { return false; } const auto &applets = m_view->containment()->applets(); for (auto *applet : applets) { const auto &provides = KPluginMetaData::readStringList(applet->pluginMetaData().rawData(), QStringLiteral("X-Plasma-Provides")); if (provides.contains(QLatin1String("org.kde.plasma.multitasking"))) { if (QQuickItem *appletInterface = applet->property("_plasma_graphicObject").value()) { const auto &childItems = appletInterface->childItems(); if (childItems.isEmpty()) { continue; } KPluginMetaData meta = applet->kPackage().metadata(); for (QQuickItem *item : childItems) { if (auto *metaObject = item->metaObject()) { int methodIndex{metaObject->indexOfMethod("ewInstanceForTaskAtIndex(QVariant)")}; if (methodIndex == -1) { continue; } QMetaMethod method = metaObject->method(methodIndex); if (method.invoke(item, Q_ARG(QVariant, index - 1))) { showShortcutBadges(false, true); return true; } } } } } } return false; } bool ContainmentInterface::activateEntry(const int index) { - identifyMainItem(); + identifyShortcutsHost(); if (!m_activateEntryMethod.isValid()) { return false; } - return m_activateEntryMethod.invoke(m_mainItem, Q_ARG(QVariant, index)); + return m_activateEntryMethod.invoke(m_shortcutsHost, Q_ARG(QVariant, index)); } bool ContainmentInterface::newInstanceForEntry(const int index) { - identifyMainItem(); + identifyShortcutsHost(); if (!m_newInstanceMethod.isValid()) { return false; } - return m_newInstanceMethod.invoke(m_mainItem, Q_ARG(QVariant, index)); + return m_newInstanceMethod.invoke(m_shortcutsHost, Q_ARG(QVariant, index)); } bool ContainmentInterface::hideShortcutBadges() { - identifyMainItem(); + identifyShortcutsHost(); if (!m_showShortcutsMethod.isValid()) { return false; } - return m_showShortcutsMethod.invoke(m_mainItem, Q_ARG(QVariant, false), Q_ARG(QVariant, false), Q_ARG(QVariant, false), Q_ARG(QVariant, -1)); + return m_showShortcutsMethod.invoke(m_shortcutsHost, Q_ARG(QVariant, false), Q_ARG(QVariant, false), Q_ARG(QVariant, false), Q_ARG(QVariant, -1)); } bool ContainmentInterface::showOnlyMeta() { if (!m_corona->universalSettings()->kwin_metaForwardedToLatte()) { return false; } return showShortcutBadges(false, true); } bool ContainmentInterface::showShortcutBadges(const bool showLatteShortcuts, const bool showMeta) { - identifyMainItem(); + identifyShortcutsHost(); if (!m_showShortcutsMethod.isValid() || !isCapableToShowShortcutBadges()) { return false; } int appLauncherId = m_corona->universalSettings()->kwin_metaForwardedToLatte() && showMeta ? applicationLauncherId() : -1; - return m_showShortcutsMethod.invoke(m_mainItem, Q_ARG(QVariant, showLatteShortcuts), Q_ARG(QVariant, true), Q_ARG(QVariant, showMeta), Q_ARG(QVariant, appLauncherId)); + return m_showShortcutsMethod.invoke(m_shortcutsHost, Q_ARG(QVariant, showLatteShortcuts), Q_ARG(QVariant, true), Q_ARG(QVariant, showMeta), Q_ARG(QVariant, appLauncherId)); } int ContainmentInterface::appletIdForVisualIndex(const int index) { - identifyMainItem(); + identifyShortcutsHost(); if (!m_appletIdForIndexMethod.isValid()) { return false; } QVariant appletId{-1}; - m_appletIdForIndexMethod.invoke(m_mainItem, Q_RETURN_ARG(QVariant, appletId), Q_ARG(QVariant, index)); + m_appletIdForIndexMethod.invoke(m_shortcutsHost, Q_RETURN_ARG(QVariant, appletId), Q_ARG(QVariant, index)); return appletId.toInt(); } void ContainmentInterface::deactivateApplets() { if (!m_view->containment() || !m_view->inReadyState()) { return; } for (const auto applet : m_view->containment()->applets()) { PlasmaQuick::AppletQuickItem *ai = applet->property("_plasma_graphicObject").value(); if (ai) { ai->setExpanded(false); } } } bool ContainmentInterface::appletIsExpandable(const int id) { if (!m_view->containment() || !m_view->inReadyState()) { return false; } for (const auto applet : m_view->containment()->applets()) { if (applet && applet->id() == (uint)id) { if (m_view->layout() && m_view->layout()->isInternalContainment(applet)) { return true; } PlasmaQuick::AppletQuickItem *ai = applet->property("_plasma_graphicObject").value(); if (ai) { return appletIsExpandable(ai); } } } return false; } bool ContainmentInterface::appletIsExpandable(PlasmaQuick::AppletQuickItem *appletQuickItem) { if (!appletQuickItem || !m_view->inReadyState()) { return false; } return (appletQuickItem->fullRepresentation() != nullptr && appletQuickItem->preferredRepresentation() != appletQuickItem->fullRepresentation()); } bool ContainmentInterface::hasExpandedApplet() const { return m_expandedAppletIds.count() > 0; } bool ContainmentInterface::hasLatteTasks() const { return (m_latteTasksModel->count() > 0); } bool ContainmentInterface::hasPlasmaTasks() const { return (m_plasmaTasksModel->count() > 0); } void ContainmentInterface::addExpandedApplet(const int &id) { if (m_expandedAppletIds.contains(id) && appletIsExpandable(id)) { return; } bool isExpanded = hasExpandedApplet(); m_expandedAppletIds << id; if (isExpanded != hasExpandedApplet()) { emit hasExpandedAppletChanged(); } emit expandedAppletStateChanged(); } void ContainmentInterface::removeExpandedApplet(const int &id) { if (!m_expandedAppletIds.contains(id)) { return; } bool isExpanded = hasExpandedApplet(); m_expandedAppletIds.removeAll(id); if (isExpanded != hasExpandedApplet()) { emit hasExpandedAppletChanged(); } emit expandedAppletStateChanged(); } QAbstractListModel *ContainmentInterface::latteTasksModel() const { return m_latteTasksModel; } QAbstractListModel *ContainmentInterface::plasmaTasksModel() const { return m_plasmaTasksModel; } void ContainmentInterface::on_appletExpandedChanged() { PlasmaQuick::AppletQuickItem *appletItem = static_cast(QObject::sender()); if (appletItem) { if (appletItem->isExpanded()) { addExpandedApplet(appletItem->applet()->id()); } else { removeExpandedApplet(appletItem->applet()->id()); } } } void ContainmentInterface::onLatteTasksCountChanged() { if ((m_hasLatteTasks && m_latteTasksModel->count()>0) || (!m_hasLatteTasks && m_latteTasksModel->count() == 0)) { return; } m_hasLatteTasks = (m_latteTasksModel->count() > 0); emit hasLatteTasksChanged(); } void ContainmentInterface::onPlasmaTasksCountChanged() { if ((m_hasPlasmaTasks && m_plasmaTasksModel->count()>0) || (!m_hasPlasmaTasks && m_plasmaTasksModel->count() == 0)) { return; } m_hasPlasmaTasks = (m_plasmaTasksModel->count() > 0); emit hasPlasmaTasksChanged(); } bool ContainmentInterface::appletIsExpanded(const int id) { return m_expandedAppletIds.contains(id); } void ContainmentInterface::toggleAppletExpanded(const int id) { if (!m_view->containment() || !m_view->inReadyState()) { return; } for (const auto applet : m_view->containment()->applets()) { if (applet->id() == (uint)id && !m_view->layout()->isInternalContainment(applet)/*block for internal containments*/) { PlasmaQuick::AppletQuickItem *ai = applet->property("_plasma_graphicObject").value(); if (ai) { if (appletIsExpandable(ai)) { ai->setExpanded(!ai->isExpanded()); } else { emit applet->activated(); } } } } } void ContainmentInterface::updateAppletsTracking() { if (!m_view->containment()) { return; } for (const auto applet : m_view->containment()->applets()) { on_appletAdded(applet); } } void ContainmentInterface::on_appletAdded(Plasma::Applet *applet) { if (!m_view->containment() || !applet) { return; } if (m_view->layout() && m_view->layout()->isInternalContainment(applet)) { //! internal containment case Plasma::Containment *internalC = m_view->layout()->internalContainmentOf(applet); PlasmaQuick::AppletQuickItem *contAi = applet->property("_plasma_graphicObject").value(); if (contAi && !m_appletsExpandedConnections.contains(contAi)) { m_appletsExpandedConnections[contAi] = connect(contAi, &PlasmaQuick::AppletQuickItem::expandedChanged, this, &ContainmentInterface::on_appletExpandedChanged); connect(contAi, &QObject::destroyed, this, [&, contAi](){ m_appletsExpandedConnections.remove(contAi); removeExpandedApplet(contAi->applet()->id()); }); } for (const auto internalApplet : internalC->applets()) { PlasmaQuick::AppletQuickItem *ai = internalApplet->property("_plasma_graphicObject").value(); if (ai && !m_appletsExpandedConnections.contains(ai) ){ m_appletsExpandedConnections[ai] = connect(ai, &PlasmaQuick::AppletQuickItem::expandedChanged, this, &ContainmentInterface::on_appletExpandedChanged); connect(ai, &QObject::destroyed, this, [&, ai](){ m_appletsExpandedConnections.remove(ai); removeExpandedApplet(ai->applet()->id()); }); } } } else { PlasmaQuick::AppletQuickItem *ai = applet->property("_plasma_graphicObject").value(); if (!ai) { return; } KPluginMetaData meta = applet->kPackage().metadata(); const auto &provides = KPluginMetaData::readStringList(meta.rawData(), QStringLiteral("X-Plasma-Provides")); if (meta.pluginId() == "org.kde.latte.plasmoid") { //! populate latte tasks applet m_latteTasksModel->addTask(ai); } else if (provides.contains(QLatin1String("org.kde.plasma.multitasking"))) { //! populate plasma tasks applet m_plasmaTasksModel->addTask(ai); } else if (!m_appletsExpandedConnections.contains(ai)) { m_appletsExpandedConnections[ai] = connect(ai, &PlasmaQuick::AppletQuickItem::expandedChanged, this, &ContainmentInterface::on_appletExpandedChanged); connect(ai, &QObject::destroyed, this, [&, ai](){ m_appletsExpandedConnections.remove(ai); removeExpandedApplet(ai->applet()->id()); }); } } } } } diff --git a/app/view/containmentinterface.h b/app/view/containmentinterface.h index 74402734..19628eb0 100644 --- a/app/view/containmentinterface.h +++ b/app/view/containmentinterface.h @@ -1,149 +1,149 @@ /* * Copyright 2019 Michail Vourlakos * * 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 . */ #ifndef VIEWCONTAINMENTINTERFACE_H #define VIEWCONTAINMENTINTERFACE_H // local #include "tasksmodel.h" // Qt #include #include #include #include #include namespace Plasma { class Applet; } namespace PlasmaQuick { class AppletQuickItem; } namespace Latte { class Corona; class View; } namespace Latte { namespace ViewPart { class ContainmentInterface: public QObject { Q_OBJECT Q_PROPERTY(bool hasExpandedApplet READ hasExpandedApplet NOTIFY hasExpandedAppletChanged) Q_PROPERTY(bool hasLatteTasks READ hasLatteTasks NOTIFY hasLatteTasksChanged) Q_PROPERTY(bool hasPlasmaTasks READ hasPlasmaTasks NOTIFY hasPlasmaTasksChanged) Q_PROPERTY(QAbstractListModel *latteTasksModel READ latteTasksModel() NOTIFY latteTasksModelChanged) Q_PROPERTY(QAbstractListModel *plasmaTasksModel READ plasmaTasksModel() NOTIFY plasmaTasksModelChanged) public: ContainmentInterface(Latte::View *parent); virtual ~ContainmentInterface(); bool hasExpandedApplet() const; bool hasLatteTasks() const; bool hasPlasmaTasks() const; bool applicationLauncherInPopup() const; bool applicationLauncherHasGlobalShortcut() const; bool containsApplicationLauncher() const; bool isCapableToShowShortcutBadges(); bool activateEntry(const int index); bool newInstanceForEntry(const int index); bool activatePlasmaTask(const int index); bool newInstanceForPlasmaTask(const int index); bool hideShortcutBadges(); bool showOnlyMeta(); bool showShortcutBadges(const bool showLatteShortcuts, const bool showMeta); //! this is updated from external apps e.g. a thunderbird plugin bool updateBadgeForLatteTask(const QString identifier, const QString value); int applicationLauncherId() const; int appletIdForVisualIndex(const int index); QAbstractListModel *latteTasksModel() const; QAbstractListModel *plasmaTasksModel() const; public slots: Q_INVOKABLE void deactivateApplets(); Q_INVOKABLE void toggleAppletExpanded(const int id); Q_INVOKABLE bool appletIsExpandable(const int id); Q_INVOKABLE bool appletIsExpanded(const int id); signals: void expandedAppletStateChanged(); void hasExpandedAppletChanged(); void hasLatteTasksChanged(); void hasPlasmaTasksChanged(); void latteTasksModelChanged(); void plasmaTasksModelChanged(); private slots: - void identifyMainItem(); + void identifyShortcutsHost(); void identifyMethods(); void updateAppletsTracking(); void on_appletAdded(Plasma::Applet *applet); void on_appletExpandedChanged(); void onLatteTasksCountChanged(); void onPlasmaTasksCountChanged(); private: void addExpandedApplet(const int &id); void removeExpandedApplet(const int &id); bool appletIsExpandable(PlasmaQuick::AppletQuickItem *appletQuickItem); private: bool m_hasLatteTasks{false}; bool m_hasPlasmaTasks{false}; QMetaMethod m_activateEntryMethod; QMetaMethod m_appletIdForIndexMethod; QMetaMethod m_newInstanceMethod; QMetaMethod m_showShortcutsMethod; QPointer m_corona; QPointer m_view; - QPointer m_mainItem; + QPointer m_shortcutsHost; //! startup timer to initialize //! applets tracking QTimer m_appletsExpandedConnectionsTimer; TasksModel *m_latteTasksModel; TasksModel *m_plasmaTasksModel; QHash m_appletsExpandedConnections; QList m_expandedAppletIds; }; } } #endif diff --git a/containment/package/contents/ui/abilities/Indexer.qml b/containment/package/contents/ui/abilities/Indexer.qml index 1b32804f..5accf64c 100644 --- a/containment/package/contents/ui/abilities/Indexer.qml +++ b/containment/package/contents/ui/abilities/Indexer.qml @@ -1,57 +1,78 @@ /* * Copyright 2020 Michail Vourlakos * * 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 . */ import QtQuick 2.7 import org.kde.plasma.plasmoid 2.0 import "./privates" as Ability Ability.IndexerPrivate { + objectName: "IndexerAbilityHost" + //! do not update during dragging/moving applets inConfigureAppletsMode updateIsBlocked: (root.dragOverlay && root.dragOverlay.pressed) || layouter.appletsInParentChange function getClientBridge(index) { if (clientsBridges.length<=0) { return false; } var ibl = clientsBridges.length; for(var i=0; i= 0) || (hidden.indexOf(actualIndex) >= 0)) { - return -1; + function appletIdForVisibleIndex(itemVisibleIndex) { + var sLayout = layouts.startLayout; + for (var i=0; i * * 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 . */ import QtQuick 2.8 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.plasmoid 2.0 import "./privates" as Ability Ability.PositionShortcutsPrivate { + id: _shortcuts + objectName: "PositionShortcutsAbilityHost" + //! do not update during dragging/moving applets inConfigureAppletsMode + updateIsBlocked: (root.dragOverlay && root.dragOverlay.pressed) + || layouter.appletsInParentChange + + + //! this is called from globalshortcuts c++ side + function setShowAppletShortcutBadges(showPositionShortcuts, showShortcuts, showMeta, applicationLauncher){ + showPositionShortcutBadges = showPositionShortcuts; + showAppletShortcutBadges = showShortcuts; + showMetaBadge = showMeta; + applicationLauncherId = applicationLauncher; + } + + //! this is called from Latte::View::ContainmentInterface + function activateEntryAtIndex(index) { + if (typeof index !== "number") { + return; + } + + sglActivateEntryAtIndex(index); + } + + //! this is called from Latte::View::ContainmentInterface + function newInstanceForEntryAtIndex(index) { + if (typeof index !== "number") { + return; + } + + sglNewInstanceForEntryAtIndex(index); + } + + //! this is called from Latte::View::ContainmentInterface + function appletIdForIndex(index) { + return indexer.appletIdForVisibleIndex(index); + } } diff --git a/containment/package/contents/ui/abilities/privates/IndexerPrivate.qml b/containment/package/contents/ui/abilities/privates/IndexerPrivate.qml index cc9d2dd4..9117bc36 100644 --- a/containment/package/contents/ui/abilities/privates/IndexerPrivate.qml +++ b/containment/package/contents/ui/abilities/privates/IndexerPrivate.qml @@ -1,220 +1,252 @@ /* * Copyright 2020 Michail Vourlakos * * 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 . */ import QtQuick 2.7 import org.kde.plasma.plasmoid 2.0 import org.kde.latte.abilities.definitions 0.1 as AbilityDefinition AbilityDefinition.Indexer { id: indxr - property Item layouts: null - property bool updateIsBlocked: false property var clients: [] property var clientsBridges: [] Binding{ target: indxr property: "separators" when: !updateIsBlocked value: { var seps = []; var sLayout = layouts.startLayout; for (var i=0; i=0) { seps.push(appletItem.index); } } var mLayout = layouts.mainLayout; for (var i=0; i=0) { seps.push(appletItem.index); } } var eLayout = layouts.endLayout; for (var i=0; i=0) { seps.push(appletItem.index); } } return seps; } } Binding { target: indxr property: "hidden" when: !updateIsBlocked value: { var hdn = []; var sLayout = layouts.startLayout; for (var i=0; i=0) { hdn.push(appletItem.index); } } var mLayout = layouts.mainLayout; for (var i=0; i=0) { hdn.push(appletItem.index); } } var eLayout = layouts.endLayout; for (var i=0; i=0) { hdn.push(appletItem.index); } } return hdn; } } Binding { target: indxr property: "clients" when: !updateIsBlocked value: { var clns = []; var sLayout = layouts.startLayout; for (var i=0; i=0 && appletItem.communicator && appletItem.communicator.indexerIsSupported) { clns.push(appletItem.index); } } var mLayout = layouts.mainLayout; for (var i=0; i=0 && appletItem.communicator && appletItem.communicator.indexerIsSupported) { clns.push(appletItem.index); } } var eLayout = layouts.endLayout; for (var i=0; i=0 && appletItem.communicator && appletItem.communicator.indexerIsSupported) { clns.push(appletItem.index); } } return clns; } } Binding { target: indxr property: "clientsBridges" when: !updateIsBlocked value: { var bdgs = []; var sLayout = layouts.startLayout; for (var i=0; i=0 && appletItem.communicator && appletItem.communicator.indexerIsSupported && appletItem.communicator.bridge && appletItem.communicator.bridge.indexer) { bdgs.push(appletItem.communicator.bridge.indexer); } } var mLayout = layouts.mainLayout; for (var i=0; i=0 && appletItem.communicator && appletItem.communicator.indexerIsSupported && appletItem.communicator.bridge && appletItem.communicator.bridge.indexer) { bdgs.push(appletItem.communicator.bridge.indexer); } } var eLayout = layouts.endLayout; for (var i=0; i=0 && appletItem.communicator && appletItem.communicator.indexerIsSupported && appletItem.communicator.bridge && appletItem.communicator.bridge.indexer) { bdgs.push(appletItem.communicator.bridge.indexer); } } return bdgs; } } function visibleItemsBeforeCount(layout, actualIndex) { var visibleItems = 0; for (var i=0; i= 0) || (hidden.indexOf(appletItem.index) >= 0)) { //! ignore hidden and separators applets continue; } else if (!appletItem.communicator || !appletItem.communicator.indexerIsSupported) { //! single item applet visibleItems = visibleItems + 1; } else if (appletItem.communicator && appletItem.communicator.indexerIsSupported) { //! multi items applet visibleItems = visibleItems + appletItem.communicator.bridge.indexer.client.visibleItemsCount; } } } return visibleItems; } + + function visibleIndex(actualIndex) { + if ((separators.indexOf(actualIndex) >= 0) || (hidden.indexOf(actualIndex) >= 0)) { + return -1; + } + + var visibleItems = visibleItemsBeforeCount(layouts.startLayout, actualIndex) + + visibleItemsBeforeCount(layouts.mainLayout, actualIndex) + + visibleItemsBeforeCount(layouts.endLayout, actualIndex); + + return visibleItems; + } + + function visibleIndexBelongsAtApplet(applet, itemVisibleIndex) { + if (itemVisibleIndex<0 || !applet) { + return false; + } + + var vIndexBase = visibleIndex(applet.index); + + if (vIndexBase === itemVisibleIndex) { + return true; + } else if (applet.communicator + && applet.communicator.indexerIsSupported + && applet.communicator.bridge + && applet.communicator.bridge.indexer) { + if (itemVisibleIndex >= vIndexBase + && itemVisibleIndex< (vIndexBase + appletItem.communicator.bridge.indexer.client.visibleItemsCount)) { + return true; + } + } + + return false; + } } diff --git a/containment/package/contents/ui/abilities/privates/PositionShortcutsPrivate.qml b/containment/package/contents/ui/abilities/privates/PositionShortcutsPrivate.qml index 9d0e1089..e25a0a40 100644 --- a/containment/package/contents/ui/abilities/privates/PositionShortcutsPrivate.qml +++ b/containment/package/contents/ui/abilities/privates/PositionShortcutsPrivate.qml @@ -1,115 +1,83 @@ /* * Copyright 2020 Michail Vourlakos * * 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 . */ import QtQuick 2.7 Item { - objectName: "PositionShortcuts" + id: _shortcutsprivate + property Item layouts: null + property bool updateIsBlocked: false - property bool unifiedGlobalShortcuts: true + readonly property bool unifiedGlobalShortcuts: appletIdStealingPositionShortcuts === -1 - property bool showLatteShortcutBadges: false + property bool showPositionShortcutBadges: false property bool showAppletShortcutBadges: false property bool showMetaBadge: false property int applicationLauncherId: -1 + property int appletIdStealingPositionShortcuts: -1 + signal sglActivateEntryAtIndex(int entryIndex); signal sglNewInstanceForEntryAtIndex(int entryIndex); - //! this is called from globalshortcuts c++ side - function setShowAppletShortcutBadges(showLatteShortcuts, showShortcuts, showMeta, applicationLauncher){ - if (latteApplet) { - var base = unifiedGlobalShortcuts ? parabolicManager.pseudoAppletIndex(latteAppletPos) : 1; - latteApplet.setTasksBaseIndex(base - 1); - latteApplet.setShowTaskShortcutBadges(showLatteShortcuts); - } - - showLatteShortcutBadges = showLatteShortcuts; - showAppletShortcutBadges = showShortcuts; - showMetaBadge = showMeta; - applicationLauncherId = applicationLauncher; - - if (latteApplet) { - latteApplet.parabolicManager.updateTasksEdgesIndexes(); - } - } - - //! this is called from Latte::View::ContainmentInterface - function activateEntryAtIndex(index) { - if (typeof index !== "number") { - return; - } - - if (latteApplet) { - var base = unifiedGlobalShortcuts ? parabolicManager.pseudoAppletIndex(latteAppletPos) : 1; - latteApplet.setTasksBaseIndex(base - 1); - latteApplet.parabolicManager.updateTasksEdgesIndexes(); - } - - signalActivateEntryAtIndex(index); - } - - //! this is called from Latte::View::ContainmentInterface - function newInstanceForEntryAtIndex(index) { - if (typeof index !== "number") { - return; - } - - if (latteApplet) { - var base = unifiedGlobalShortcuts ? parabolicManager.pseudoAppletIndex(latteAppletPos) : 1; - latteApplet.setTasksBaseIndex(base - 1); - latteApplet.parabolicManager.updateTasksEdgesIndexes(); - } - - signalNewInstanceForEntryAtIndex(index); - } - - //! this is called from Latte::View::ContainmentInterface - function appletIdForIndex(index) { - if (!root.unifiedGlobalShortcuts || parabolicManager.pseudoIndexBelongsToLatteApplet(index)) { - return -1; - } - - for (var i=0; i=0 + && appletItem.communicator + && appletItem.communicator.onPositionShortcutsAreSupported + && appletItem.communicator.bridge.shortcuts.client.isStealingGlobalPositionShortcuts) { + return appletItem.index; + } } - } - - for (var j=0; j=0 + && appletItem.communicator + && appletItem.communicator.onPositionShortcutsAreSupported + && appletItem.communicator.bridge.shortcuts.client.isStealingGlobalPositionShortcuts) { + return appletItem.index; + } } - } - - for (var k=0; j=0 + && appletItem.communicator + && appletItem.communicator.onPositionShortcutsAreSupported + && appletItem.communicator.bridge.shortcuts.client.isStealingGlobalPositionShortcuts) { + return appletItem.index; + } } - } - return -1; + return -1; + } } } diff --git a/containment/package/contents/ui/applet/AppletItem.qml b/containment/package/contents/ui/applet/AppletItem.qml index ee2d9d55..ef329b53 100644 --- a/containment/package/contents/ui/applet/AppletItem.qml +++ b/containment/package/contents/ui/applet/AppletItem.qml @@ -1,1198 +1,1199 @@ /* * Copyright 2016 Smith AR * Michail Vourlakos * * 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 . */ import QtQuick 2.7 import QtQuick.Layouts 1.1 import QtGraphicalEffects 1.0 import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.kquickcontrolsaddons 2.0 import org.kde.latte.core 0.2 as LatteCore import org.kde.latte.components 1.0 as LatteComponents import "colorizer" as Colorizer import "communicator" as Communicator import "indicator" as Indicator import "../debug" as Debug Item { id: appletItem visible: false width: isInternalViewSplitter && !root.inConfigureAppletsMode ? 0 : computeWidth height: isInternalViewSplitter && !root.inConfigureAppletsMode ? 0 : computeHeight //any applets that exceed their limits should not take events from their surrounding applets clip: !isSeparator signal mousePressed(int x, int y, int button); signal mouseReleased(int x, int y, int button); property bool animationsEnabled: true property bool parabolicEffectIsSupported: true property bool canShowAppletNumberBadge: !isSeparator && !isHidden && !isLattePlasmoid && !isSpacer && !isInternalViewSplitter //! Fill Applet(s) property bool inFillCalculations: false //temp record, is used in calculations for fillWidth,fillHeight applets property bool isAutoFillApplet: { if (!applet || !applet.Layout) return false; if (((root.isHorizontal && applet.Layout.fillWidth===true) || (root.isVertical && applet.Layout.fillHeight===true)) && (applet.status !== PlasmaCore.Types.HiddenStatus)) return true; else return false; } property int maxAutoFillLength: -1 //it is used in calculations for fillWidth,fillHeight applets property int minAutoFillLength: -1 //it is used in calculations for fillWidth,fillHeight applets property bool userBlocksColorizing: false property bool appletBlocksColorizing: !communicator.requires.latteSideColoringEnabled property bool appletBlocksParabolicEffect: communicator.requires.parabolicEffectLocked property bool lockZoom: false property bool isActive: (isExpanded && applet.pluginName !== root.plasmoidName && applet.pluginName !== "org.kde.activeWindowControl" && applet.pluginName !== "org.kde.plasma.appmenu") property bool isExpanded: false property bool isHidden: (applet && applet.status === PlasmaCore.Types.HiddenStatus) || (isInternalViewSplitter && !root.inConfigureAppletsMode) property bool isInternalViewSplitter: (internalSplitterId > 0) property bool isLattePlasmoid: latteApplet !== null property bool isZoomed: false property bool isSeparator: applet && (applet.pluginName === "audoban.applet.separator" || applet.pluginName === "org.kde.latte.separator") property bool isSpacer: applet && (applet.pluginName === "org.kde.latte.spacer") property bool isSystray: applet && (applet.pluginName === "org.kde.plasma.systemtray" || applet.pluginName === "org.nomad.systemtray" ) property bool firstChildOfStartLayout: index === appletItem.layouter.startLayout.firstVisibleIndex property bool firstChildOfMainLayout: index === appletItem.layouter.mainLayout.firstVisibleIndex property bool lastChildOfMainLayout: index === appletItem.layouter.mainLayout.lastVisibleIndex property bool lastChildOfEndLayout: index === appletItem.layouter.endLayout.lastVisibleIndex readonly property bool atScreenEdge: { if (root.panelAlignment !== LatteCore.Types.Justify || root.inConfigureAppletsMode || plasmoid.configuration.offset!==0) { return false; } if (root.panelAlignment === LatteCore.Types.Justify) { //! Justify case if (root.maxLengthPerCentage!==100) { return false; } if (root.isHorizontal) { if (firstChildOfStartLayout) { return latteView && latteView.x === latteView.screenGeometry.x; } else if (lastChildOfEndLayout) { return latteView && ((latteView.x + latteView.width) === (latteView.screenGeometry.x + latteView.screenGeometry.width)); } } else { if (firstChildOfStartLayout) { return latteView && latteView.y === latteView.screenGeometry.y; } else if (lastChildOfEndLayout) { return latteView && ((latteView.y + latteView.height) === (latteView.screenGeometry.y + latteView.screenGeometry.height)); } } return false; } //! [disabled] because it is probably not needed at all. If in the future there is a report //! describing a case that this would be useful this disablement choice can be rethought /*if (root.panelAlignment === LatteCore.Types.Left) { //! Left case return firstChildOfMainLayout; } else if (root.panelAlignment === LatteCore.Types.Right) { //! Right case return lastChildOfMainLayout } if (root.panelAlignment === LatteCore.Types.Top) { return firstChildOfMainLayout && latteView && latteView.y === latteView.screenGeometry.y; } else if (root.panelAlignment === LatteCore.Types.Bottom) { return lastChildOfMainLayout && latteView && ((latteView.y + latteView.height) === (latteView.screenGeometry.y + latteView.screenGeometry.height)); }*/ return false; } //applet is in starting edge property bool firstAppletInContainer: (index >=0) && ((index === layouter.startLayout.firstVisibleIndex) || (index === layouter.mainLayout.firstVisibleIndex) || (index === layouter.endLayout.firstVisibleIndex)) //applet is in ending edge property bool lastAppletInContainer: (index >=0) && ((index === layouter.startLayout.lastVisibleIndex) || (index === layouter.mainLayout.lastVisibleIndex) || (index === layouter.endLayout.lastVisibleIndex)) readonly property bool acceptMouseEvents: applet && !isLattePlasmoid && !originalAppletBehavior && !appletItem.isSeparator && !communicator.requires.parabolicEffectLocked readonly property bool originalAppletBehavior: (appletItem.parabolic.factor.zoom === 1 && !lockZoom /*hacky flag to keep Latte behavior*/) || (appletItem.parabolic.factor.zoom>1 && !parabolicEffectIsSupported) || (appletItem.parabolic.factor.zoom>1 && parabolicEffectIsSupported && lockZoom) readonly property bool isSquare: communicator.overlayLatteIconIsActive readonly property bool screenEdgeMarginSupported: communicator.requires.screenEdgeMarginSupported property int animationTime: appletItem.animations.speedFactor.normal * (1.2*appletItem.animations.duration.small) property int index: -1 property int maxWidth: root.isHorizontal ? root.height : root.width property int maxHeight: root.isHorizontal ? root.height : root.width property int internalSplitterId: 0 property int previousIndex: -1 property int spacersMaxSize: Math.max(0,Math.ceil(0.55 * metrics.iconSize) - metrics.totals.lengthEdges) property int status: applet ? applet.status : -1 //! separators tracking readonly property bool tailAppletIsSeparator: { if (isSeparator || index<0) { return false; } var tail = index - 1; while(tail>=0 && indexer.hidden.indexOf(tail)>=0) { //! when a tail applet contains sub-indexing and does not influence //! tracking is considered hidden tail = tail - 1; } if (tail >= 0 && indexer.clients.indexOf(tail)>=0) { //! tail applet contains items sub-indexing var tailBridge = indexer.getClientBridge(tail); if (tailBridge && tailBridge.client) { return tailBridge.client.lastHeadItemIsSeparator; } } // tail applet is normal return (indexer.separators.indexOf(tail)>=0); } readonly property bool headAppletIsSeparator: { if (isSeparator || index<0) { return false; } var head = index + 1; while(head>=0 && indexer.hidden.indexOf(head)>=0) { //! when a head applet contains sub-indexing and does not influence //! tracking is considered hidden head = head + 1; } if (head >= 0 && indexer.clients.indexOf(head)>=0) { //! head applet contains items sub-indexing var headBridge = indexer.getClientBridge(head); if (headBridge && headBridge.client) { return headBridge.client.firstTailItemIsSeparator; } } // head applet is normal return (indexer.separators.indexOf(head)>=0); } //! local margins readonly property bool parabolicEffectMarginsEnabled: appletItem.parabolic.factor.zoom>1 && !originalAppletBehavior && !communicator.parabolicEffectIsSupported property int lengthAppletPadding: metrics.fraction.lengthAppletPadding === -1 || parabolicEffectMarginsEnabled ? metrics.padding.length : metrics.padding.lengthApplet property int lengthAppletFullMargin: 0 property int lengthAppletFullMargins: 2 * lengthAppletFullMargin property int internalWidthMargins: { if (root.isVertical) { return metrics.totals.thicknessEdges; } /*TODO, Fitt's case: is temporary until the atScreenEdge applets are aligned properly to the corner and the wrapper is taking all the space needed in order to fill right. For atScreenEdge appplets that should be: applet size + lengthAppletPadding + lengthAppletExtMargin. The indicator should follow also the applet alignment in this in order to feel right */ return 2 * lengthAppletPadding; } property int internalHeightMargins: { if (root.isHorizontal) { return root.metrics.totals.thicknessEdges; } /*TODO,Fitt's case: is temporary until the atScreenEdge applets are aligned properly to the corner and the wrapper is taking all the space needed in order to fill right. For atScreenEdge appplets that should be: applet size + lengthAppletPadding + lengthAppletExtMargin. The indicator should follow also the applet alignment in this in order to feel right */ return 2 * lengthAppletPadding; } //! are set by the indicator property int iconOffsetX: 0 property int iconOffsetY: 0 property real computeWidth: root.isVertical ? wrapper.width : hiddenSpacerLeft.width+wrapper.width+hiddenSpacerRight.width property real computeHeight: root.isVertical ? hiddenSpacerLeft.height + wrapper.height + hiddenSpacerRight.height : wrapper.height property string title: isInternalViewSplitter ? "Now Dock Splitter" : "" property Item applet: null property Item latteApplet: applet && (applet.pluginName === root.plasmoidName) ? (applet.children[0] ? applet.children[0] : null) : null property Item latteStyleApplet: applet && ((applet.pluginName === "org.kde.latte.spacer") || (applet.pluginName === "org.kde.latte.separator")) ? (applet.children[0] ? applet.children[0] : null) : null property Item appletWrapper: applet && (applet.pluginName === root.plasmoidName )? wrapper : wrapper.wrapperContainer property Item tooltipVisualParent: titleTooltipParent readonly property alias communicator: _communicator readonly property alias wrapper: _wrapper property Item animations: null property Item indexer: null property Item layouter: null property Item metrics: null property Item parabolic: null + property Item shortcuts: null property bool containsMouse: appletMouseArea.containsMouse || (isLattePlasmoid && latteApplet.containsMouse) property bool pressed: viewSignalsConnector.pressed || clickedAnimation.running //// BEGIN :: Animate Applet when a new applet is dragged in the view //when the applet moves caused by its resize, don't animate. //this is completely heuristic, but looks way less "jumpy" property bool movingForResize: false property int oldX: x property int oldY: y onXChanged: { if (root.isVertical) { return; } if (movingForResize) { movingForResize = false; return; } var draggingAppletInConfigure = root.dragOverlay && root.dragOverlay.currentApplet; var isCurrentAppletInDragging = draggingAppletInConfigure && (root.dragOverlay.currentApplet === appletItem); var dropApplet = root.dragInfo.entered && foreDropArea.visible if (isCurrentAppletInDragging || !draggingAppletInConfigure && !dropApplet) { return; } if (!root.isVertical) { translation.x = oldX - x; translation.y = 0; } else { translation.y = oldY - y; translation.x = 0; } translAnim.running = true if (!root.isVertical) { oldX = x; oldY = 0; } else { oldY = y; oldX = 0; } } onYChanged: { if (root.isHorizontal) { return; } if (movingForResize) { movingForResize = false; return; } var draggingAppletInConfigure = root.dragOverlay && root.dragOverlay.currentApplet; var isCurrentAppletInDragging = draggingAppletInConfigure && (root.dragOverlay.currentApplet === appletItem); var dropApplet = root.dragInfo.entered && foreDropArea.visible if (isCurrentAppletInDragging || !draggingAppletInConfigure && !dropApplet) { return; } if (!root.isVertical) { translation.x = oldX - x; translation.y = 0; } else { translation.y = oldY - y; translation.x = 0; } translAnim.running = true; if (!root.isVertical) { oldX = x; oldY = 0; } else { oldY = y; oldX = 0; } } transform: Translate { id: translation } NumberAnimation { id: translAnim duration: appletItem.animations.duration.large easing.type: Easing.InOutQuad target: translation properties: "x,y" to: 0 } Behavior on lengthAppletPadding { NumberAnimation { duration: 0.8 * appletItem.animations.duration.proposed easing.type: Easing.OutCubic } } //// END :: Animate Applet when a new applet is dragged in the view /// BEGIN functions function activateAppletForNeutralAreas(mouse){ //if the event is at the active indicator or spacers area then try to expand the applet, //unfortunately for other applets there is no other way to activate them yet //for example the icon-only applets var choords = mapToItem(appletItem.appletWrapper, mouse.x, mouse.y); var wrapperContainsMouse = choords.x>=0 && choords.y>=0 && choords.x=0 && mouse.y>=0 && mouse.x0); var appletNeutralAreaEnabled = !(inThicknessNeutralArea && root.dragActiveWindowEnabled); if (appletItemContainsMouse && !wrapperContainsMouse && appletNeutralAreaEnabled) { //console.log("PASSED"); latteView.extendedInterface.toggleAppletExpanded(applet.id); } else { //console.log("REJECTED"); } } function checkIndex(){ index = -1; for(var i=0; i maxSize || applet.Layout.minimumWidth > maxForMinimumSize)) || (applet && root.isVertical && (applet.height > maxSize || applet.Layout.minimumHeight > maxForMinimumSize))) && !appletItem.isSpacer && !communicator.canShowOverlaiedLatteIcon) ) { appletItem.parabolicEffectIsSupported = false; } else { appletItem.parabolicEffectIsSupported = true; } } } function slotDestroyInternalViewSplitters() { if (isInternalViewSplitter) { destroy(); } } //! pos in global root positioning function containsPos(pos) { var relPos = root.mapToItem(appletItem,pos.x, pos.y); if (relPos.x>=0 && relPos.x<=width && relPos.y>=0 && relPos.y<=height) return true; return false; } function refersEntryIndex(entryIndex) { return (entryIndex === parabolicManager.pseudoAppletIndex(appletItem.index)); } ///END functions //BEGIN connections onAppletChanged: { if (!applet) { destroy(); } } onIndexChanged: { if (appletItem.latteApplet) { root.latteAppletPos = index; } if (index>-1) { previousIndex = index; } } onIsExpandedChanged: { if (isExpanded) { root.hideTooltipLabel(); } } onIsSystrayChanged: { updateParabolicEffectIsSupported(); } onLatteAppletChanged: { if(appletItem.latteApplet){ root.latteApplet = appletItem.latteApplet; root.latteAppletContainer = appletItem; root.latteAppletPos = index; appletItem.latteApplet.latteView = root; appletItem.latteApplet.forceHidePanel = true; appletItem.latteApplet.signalPreviewsShown.connect(slotPreviewsShown); } } onIsAutoFillAppletChanged: updateParabolicEffectIsSupported(); Component.onCompleted: { checkIndex(); root.updateIndexes.connect(checkIndex); root.destroyInternalViewSplitters.connect(slotDestroyInternalViewSplitters); parabolic.sglClearZoom.connect(sltClearZoom); } Component.onDestruction: { appletItem.animations.needBothAxis.removeEvent(appletItem); if(root.latteAppletPos>=0 && root.latteAppletPos === index){ root.latteApplet = null; root.latteAppletContainer = null; root.latteAppletPos = -1; } root.updateIndexes.disconnect(checkIndex); root.destroyInternalViewSplitters.disconnect(slotDestroyInternalViewSplitters); parabolic.sglClearZoom.disconnect(sltClearZoom); if (appletItem.latteApplet) { appletItem.latteApplet.signalPreviewsShown.disconnect(slotPreviewsShown); } } //! Bindings Binding { //! is used to aboid loop binding warnings on startup target: appletItem property: "lengthAppletFullMargin" when: !communicator.inStartup value: lengthAppletPadding + metrics.margin.length; } //! Connections Connections{ - target: root + target: appletItem.shortcuts - onSignalActivateEntryAtIndex: { + onSglActivateEntryAtIndex: { if (parabolicManager.pseudoIndexBelongsToLatteApplet(entryIndex) && appletItem.isLattePlasmoid) { latteApplet.activateTaskAtIndex(entryIndex - latteApplet.tasksBaseIndex); - } else if (root.unifiedGlobalShortcuts && refersEntryIndex(entryIndex)) { + } else if (shortcuts.unifiedGlobalShortcuts && refersEntryIndex(entryIndex)) { latteView.extendedInterface.toggleAppletExpanded(applet.id); } } - onSignalNewInstanceForEntryAtIndex: { + onSglNewInstanceForEntryAtIndex: { if (parabolicManager.pseudoIndexBelongsToLatteApplet(entryIndex) && appletItem.isLattePlasmoid) { latteApplet.newInstanceForTaskAtIndex(entryIndex - latteApplet.tasksBaseIndex); - } else if (root.unifiedGlobalShortcuts && refersEntryIndex(entryIndex)) { + } else if (shortcuts.unifiedGlobalShortcuts && refersEntryIndex(entryIndex)) { latteView.extendedInterface.toggleAppletExpanded(applet.id); } } } Connections { id: viewSignalsConnector target: root.latteView ? root.latteView : null enabled: !appletItem.isLattePlasmoid && !appletItem.isSeparator && !appletItem.isSpacer && !appletItem.isHidden property bool pressed: false property bool blockWheel: false onMousePressed: { if (appletItem.containsPos(pos)) { viewSignalsConnector.pressed = true; var local = appletItem.mapFromItem(root, pos.x, pos.y); appletItem.mousePressed(local.x, local.y, button); if (button === Qt.LeftButton) { appletItem.activateAppletForNeutralAreas(local); } } } onMouseReleased: { if (appletItem.containsPos(pos)) { viewSignalsConnector.pressed = false; var local = appletItem.mapFromItem(root, pos.x, pos.y); appletItem.mouseReleased(local.x, local.y, button); } } onWheelScrolled: { if (!appletItem.applet || !root.mouseWheelActions || viewSignalsConnector.blockWheel || (root.latteViewIsHidden || root.inSlidingIn || root.inSlidingOut)) { return; } blockWheel = true; scrollDelayer.start(); if (appletItem.containsPos(pos) && root.latteView.extendedInterface.appletIsExpandable(applet.id)) { var angle = angleDelta.y / 8; var expanded = root.latteView.extendedInterface.appletIsExpanded(applet.id); if ((angle > 12 && !expanded) /*positive direction*/ || (angle < -12 && expanded) /*negative direction*/) { latteView.extendedInterface.toggleAppletExpanded(applet.id); } } } } Connections { target: root.latteView ? root.latteView.extendedInterface : null enabled: !appletItem.isLattePlasmoid && !appletItem.isSeparator && !appletItem.isSpacer && !appletItem.isHidden onExpandedAppletStateChanged: { if (latteView.extendedInterface.hasExpandedApplet && appletItem.applet) { appletItem.isExpanded = latteView.extendedInterface.appletIsExpandable(appletItem.applet.id) && latteView.extendedInterface.appletIsExpanded(appletItem.applet.id); } else { appletItem.isExpanded = false; } } } ///END connections //! It is used for any communication needed with the underlying applet Communicator.Engine{ id: _communicator //set up the overlayed appletItems and properties for when a overlaiedIconItem must be presented to the user //because the plasma widgets specific implementation breaks the Latte experience onOverlayLatteIconIsActiveChanged:{ if (!overlayLatteIconIsActive && applet.opacity===0) { applet.opacity = 1; } else if (overlayLatteIconIsActive && applet.opacity>0) { applet.opacity = 0; if (applet.pluginName === "org.kde.plasma.folder") { applet.parent = wrapper.containerForOverlayIcon; applet.anchors.fill = wrapper.containerForOverlayIcon; } } } } /* Rectangle{ anchors.fill: parent color: "transparent" border.color: "green" border.width: 1 }*/ /* DEPRECATED in favor of VIEW::MouseSignalsTracking MouseArea{ id: appletMouseAreaBottom anchors.fill: parent propagateComposedEvents: true visible: (!appletMouseArea.visible || !appletMouseArea.enabled) && !root.editMode && !originalAppletBehavior onPressed: { appletItem.activateAppletForNeutralAreas(mouse); mouse.accepted = false; } onReleased: { mouse.accepted = false; } }*/ //! Main Applet Shown Area Flow{ id: appletFlow width: appletItem.computeWidth height: appletItem.computeHeight // a hidden spacer for the first element to add stability // IMPORTANT: hidden spacers must be tested on vertical !!! HiddenSpacer{id: hiddenSpacerLeft} Item { width: wrapper.width height: wrapper.height Indicator.Bridge{ id: indicatorBridge } //! Indicator Back Layer Indicator.Loader{ id: indicatorBackLayer level: Indicator.LevelOptions { id: backLevelOptions isBackground: true bridge: indicatorBridge Binding { target: appletItem property: "iconOffsetX" value: backLevelOptions.requested.iconOffsetX } Binding { target: appletItem property: "iconOffsetY" value: backLevelOptions.requested.iconOffsetY } } } ItemWrapper{ id: _wrapper TitleTooltipParent{ id: titleTooltipParent metrics: appletItem.metrics parabolic: appletItem.parabolic } } //! The Applet Colorizer Colorizer.Applet { id: appletColorizer anchors.fill: parent opacity: mustBeShown ? 1 : 0 readonly property bool mustBeShown: colorizerManager.mustBeShown && !appletItem.userBlocksColorizing && !appletItem.appletBlocksColorizing && !appletItem.isInternalViewSplitter Behavior on opacity { NumberAnimation { duration: 1.2 * appletItem.animations.duration.proposed easing.type: Easing.OutCubic } } } //! Indicator Front Layer Indicator.Loader{ id: indicatorFrontLayer level: Indicator.LevelOptions { isForeground: true bridge: indicatorBridge } } //! Applet Shortcut Visual Badge Item { id: shortcutBadgeContainer width: { if (root.isHorizontal) { return appletItem.metrics.iconSize * wrapper.zoomScale } else { return badgeThickness; } } height: { if (root.isHorizontal) { return badgeThickness; } else { return appletItem.metrics.iconSize * wrapper.zoomScale } } readonly property int badgeThickness: { if (plasmoid.location === PlasmaCore.Types.BottomEdge || plasmoid.location === PlasmaCore.Types.RightEdge) { return ((appletItem.metrics.iconSize + appletItem.metrics.margin.thickness) * wrapper.zoomScale) + appletItem.metrics.margin.screenEdge; } return ((appletItem.metrics.iconSize + appletItem.metrics.margin.thickness) * wrapper.zoomScale); } ShortcutBadge{ anchors.fill: parent } states:[ State{ name: "horizontal" when: plasmoid.formFactor === PlasmaCore.Types.Horizontal AnchorChanges{ target: shortcutBadgeContainer; anchors.horizontalCenter: parent.horizontalCenter; anchors.verticalCenter: undefined; anchors.right: undefined; anchors.left: undefined; anchors.top: undefined; anchors.bottom: parent.bottom; } }, State{ name: "vertical" when: plasmoid.formFactor === PlasmaCore.Types.Vertical AnchorChanges{ target: shortcutBadgeContainer; anchors.horizontalCenter: undefined; anchors.verticalCenter: parent.verticalCenter; anchors.right: parent.right; anchors.left: undefined; anchors.top: undefined; anchors.bottom: undefined; } } ] } } // a hidden spacer on the right for the last item to add stability HiddenSpacer{id: hiddenSpacerRight; rightSpacer: true} }// Flow with hidden spacers inside //Busy Indicator PlasmaComponents.BusyIndicator { z: 1000 visible: applet && applet.busy running: visible anchors.centerIn: parent width: Math.min(parent.width, parent.height) height: width } Loader { id: addingAreaLoader width: root.isHorizontal ? parent.width : parent.width - appletItem.metrics.margin.screenEdge height: root.isHorizontal ? parent.height - appletItem.metrics.margin.screenEdge : parent.height active: isLattePlasmoid sourceComponent: LatteComponents.AddingArea{ id: addingAreaItem anchors.fill: parent // width: root.isHorizontal ? parent.width : parent.width - appletItem.metrics.margin.screenEdge // height: root.isHorizontal ? parent.height - appletItem.metrics.margin.screenEdge : parent.height radius: appletItem.metrics.iconSize/10 opacity: root.addLaunchersMessage ? 1 : 0 backgroundOpacity: 0.75 duration: appletItem.animations.speedFactor.current title: i18n("Tasks Area") } //! AddingAreaItem States states:[ State{ name: "bottom" when: plasmoid.location === PlasmaCore.Types.BottomEdge AnchorChanges{ target: addingAreaLoader anchors.horizontalCenter: parent.horizontalCenter; anchors.verticalCenter: undefined; anchors.right: undefined; anchors.left: undefined; anchors.top: undefined; anchors.bottom: parent.bottom; } PropertyChanges{ target: addingAreaLoader anchors.leftMargin: 0; anchors.rightMargin: 0; anchors.topMargin:0; anchors.bottomMargin: appletItem.metrics.margin.screenEdge; anchors.horizontalCenterOffset: 0; anchors.verticalCenterOffset: 0; } }, State{ name: "top" when: plasmoid.location === PlasmaCore.Types.TopEdge AnchorChanges{ target: addingAreaLoader anchors.horizontalCenter: parent.horizontalCenter; anchors.verticalCenter: undefined; anchors.right: undefined; anchors.left: undefined; anchors.top: parent.top; anchors.bottom: undefined; } PropertyChanges{ target: addingAreaLoader anchors.leftMargin: 0; anchors.rightMargin: 0; anchors.topMargin: appletItem.metrics.margin.screenEdge; anchors.bottomMargin: 0; anchors.horizontalCenterOffset: 0; anchors.verticalCenterOffset: 0; } }, State{ name: "left" when: plasmoid.location === PlasmaCore.Types.LeftEdge AnchorChanges{ target: addingAreaLoader anchors.horizontalCenter: undefined; anchors.verticalCenter: parent.verticalCenter; anchors.right: undefined; anchors.left: parent.left; anchors.top: undefined; anchors.bottom: undefined; } PropertyChanges{ target: addingAreaLoader anchors.leftMargin: appletItem.metrics.margin.screenEdge; anchors.rightMargin: 0; anchors.topMargin:0; anchors.bottomMargin: 0; anchors.horizontalCenterOffset: 0; anchors.verticalCenterOffset: 0; } }, State{ name: "right" when: plasmoid.location === PlasmaCore.Types.RightEdge AnchorChanges{ target: addingAreaLoader anchors.horizontalCenter: undefined; anchors.verticalCenter: parent.verticalCenter; anchors.right: parent.right; anchors.left: undefined; anchors.top: undefined; anchors.bottom: undefined; } PropertyChanges{ target: addingAreaLoader anchors.leftMargin: 0; anchors.rightMargin: appletItem.metrics.margin.screenEdge; anchors.topMargin:0; anchors.bottomMargin: 0; anchors.horizontalCenterOffset: 0; anchors.verticalCenterOffset: 0; } } ] } MouseArea{ id: appletMouseArea anchors.fill: parent enabled: visible hoverEnabled: latteApplet ? false : true propagateComposedEvents: true //! a way must be found in order for this be enabled //! only to support springloading for plasma 5.10 //! also on this is based the tooltips behavior by enabling it //! plasma tooltips are disabled visible: acceptMouseEvents property bool blockWheel: false onEntered: { appletItem.parabolic.stopRestoreZoomTimer(); if (restoreAnimation.running) { restoreAnimation.stop(); } if (!(isSeparator || isSpacer)) { root.showTooltipLabel(appletItem, applet.title); } if (originalAppletBehavior || communicator.requires.parabolicEffectLocked || !parabolicEffectIsSupported) { return; } if (root.isHalfShown || (root.latteApplet && (root.latteApplet.noTasksInAnimation>0 || root.latteApplet.contextMenu))) { return; } if (root.isHorizontal){ layoutsContainer.currentSpot = mouseX; wrapper.calculateScales(mouseX); } else{ layoutsContainer.currentSpot = mouseY; wrapper.calculateScales(mouseY); } } onExited:{ if (communicator.appletIconItemIsShown()) { communicator.setAppletIconItemActive(false); } root.hideTooltipLabel(); if (appletItem.parabolic.factor.zoom>1){ appletItem.parabolic.startRestoreZoomTimer(); } } onPositionChanged: { if (originalAppletBehavior || !parabolicEffectIsSupported) { mouse.accepted = false; return; } if (root.isHalfShown || (root.latteApplet && (root.latteApplet.noTasksInAnimation>0 || root.latteApplet.contextMenu))) { return; } var rapidMovement = appletItem.parabolic.lastIndex>=0 && Math.abs(appletItem.parabolic.lastIndex-index)>1; if (rapidMovement) { parabolic.setDirectRenderingEnabled(true); } if( ((wrapper.zoomScale == 1 || wrapper.zoomScale === appletItem.parabolic.factor.zoom) && !parabolic.directRenderingEnabled) || parabolic.directRenderingEnabled) { if (root.isHorizontal){ var step = Math.abs(layoutsContainer.currentSpot-mouse.x); if (step >= appletItem.animations.hoverPixelSensitivity){ layoutsContainer.currentSpot = mouse.x; wrapper.calculateScales(mouse.x); } } else{ var step = Math.abs(layoutsContainer.currentSpot-mouse.y); if (step >= appletItem.animations.hoverPixelSensitivity){ layoutsContainer.currentSpot = mouse.y; wrapper.calculateScales(mouse.y); } } } mouse.accepted = false; } //! these are needed in order for these events to be really forwarded underneath //! otherwise there were applets that did not receive them e.g. lock/logout applet //! when parabolic effect was used onPressed: mouse.accepted = false; onReleased: mouse.accepted = false; } //! Debug Elements Loader{ anchors.bottom: parent.bottom anchors.left: parent.left active: root.debugModeLayouter sourceComponent: Debug.Tag{ label.text: (root.isHorizontal ? appletItem.width : appletItem.height) + labeltext label.color: appletItem.isAutoFillApplet ? "green" : "white" readonly property string labeltext: { if (appletItem.isAutoFillApplet) { return " / max_fill:"+appletItem.maxAutoFillLength + " / min_fill:"+appletItem.minAutoFillLength; } return ""; } } } //! A timer is needed in order to handle also touchpads that probably //! send too many signals very fast. This way the signals per sec are limited. //! The user needs to have a steady normal scroll in order to not //! notice a annoying delay Timer{ id: scrollDelayer interval: 500 onTriggered: viewSignalsConnector.blockWheel = false; } //BEGIN states states: [ State { name: "left" when: (plasmoid.location === PlasmaCore.Types.LeftEdge) AnchorChanges { target: appletFlow anchors{ top:undefined; bottom:undefined; left:parent.left; right:undefined;} } }, State { name: "right" when: (plasmoid.location === PlasmaCore.Types.RightEdge) AnchorChanges { target: appletFlow anchors{ top:undefined; bottom:undefined; left:undefined; right:parent.right;} } }, State { name: "bottom" when: (plasmoid.location === PlasmaCore.Types.BottomEdge) AnchorChanges { target: appletFlow anchors{ top:undefined; bottom:parent.bottom; left:undefined; right:undefined;} } }, State { name: "top" when: (plasmoid.location === PlasmaCore.Types.TopEdge) AnchorChanges { target: appletFlow anchors{ top:parent.top; bottom:undefined; left:undefined; right:undefined;} } } ] //END states //BEGIN animations ///////Restore Zoom Animation///// ParallelAnimation{ id: restoreAnimation PropertyAnimation { target: wrapper property: "zoomScale" to: 1 duration: 3 * appletItem.animationTime easing.type: Easing.InCubic } } /////Clicked Animation///// SequentialAnimation{ id: clickedAnimation alwaysRunToEnd: true running: appletItem.isSquare && !originalAppletBehavior && appletItem.pressed && (appletItem.animations.speedFactor.current > 0) && !indicators.info.providesClickedAnimation ParallelAnimation{ PropertyAnimation { target: wrapper.clickedEffect property: "brightness" to: -0.35 duration: appletItem.animations.duration.large easing.type: Easing.OutQuad } } ParallelAnimation{ PropertyAnimation { target: wrapper.clickedEffect property: "brightness" to: 0 duration: appletItem.animations.duration.large easing.type: Easing.OutQuad } } } //END animations } diff --git a/containment/package/contents/ui/applet/ShortcutBadge.qml b/containment/package/contents/ui/applet/ShortcutBadge.qml index 8fde91dd..674f50cd 100644 --- a/containment/package/contents/ui/applet/ShortcutBadge.qml +++ b/containment/package/contents/ui/applet/ShortcutBadge.qml @@ -1,118 +1,118 @@ /* * Copyright 2019 Michail Vourlakos * * 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 . */ import QtQuick 2.1 import QtGraphicalEffects 1.0 import org.kde.latte.components 1.0 as LatteComponents Loader{ id: appletNumberLoader active: appletItem.canShowAppletNumberBadge && - (root.showLatteShortcutBadges - || root.showAppletShortcutBadges - || root.showMetaBadge && applet.id===applicationLauncherId) + (appletItem.shortcuts.showPositionShortcutBadges + || appletItem.shortcuts.showAppletShortcutBadges + || appletItem.shortcuts.showMetaBadge && applet.id===appletItem.shortcuts.applicationLauncherId) asynchronous: true visible: badgeString!=="" property int fixedIndex: -1 property string badgeString: "" onActiveChanged: { - if (active && root.showLatteShortcutBadges && root.unifiedGlobalShortcuts) { + if (active && appletItem.shortcuts.showPositionShortcutBadges && appletItem.shortcuts.unifiedGlobalShortcuts) { fixedIndex = appletItem.indexer.visibleIndex(index); } else { fixedIndex = -1; } } Component.onCompleted: { - if (active && root.showLatteShortcutBadges && root.unifiedGlobalShortcuts) { + if (active && appletItem.shortcuts.showPositionShortcutBadges && appletItem.shortcuts.unifiedGlobalShortcuts) { fixedIndex = appletItem.indexer.visibleIndex(index); } else { fixedIndex = -1; } } Binding{ target: appletNumberLoader property:"badgeString" - when: root.showMetaBadge || root.showAppletShortcutBadges + when: appletItem.shortcuts.showMetaBadge || appletItem.shortcuts.showAppletShortcutBadges value: { - if (root.showMetaBadge && applet && applet.id === applicationLauncherId) { + if (appletItem.shortcuts.showMetaBadge && applet && applet.id === appletItem.shortcuts.applicationLauncherId) { return '\u2318'; } - if (root.showAppletShortcutBadges) { + if (appletItem.shortcuts.showAppletShortcutBadges) { var plasmaShortcut = applet ? shortcutsEngine.appletShortcutBadge(applet.id) : ""; if (plasmaShortcut !== "") { return plasmaShortcut; } } if (appletNumberLoader.fixedIndex>=1 && appletNumberLoader.fixedIndex<20) { return root.badgesForActivate[appletNumberLoader.fixedIndex-1]; } else { return ""; } } } sourceComponent: Item{ Loader{ anchors.fill: appletNumber active: root.enableShadows && graphicsSystem.isAccelerated sourceComponent: DropShadow{ color: root.appShadowColor fast: true samples: 2 * radius source: appletNumber radius: root.appShadowSize/2 verticalOffset: 2 } } LatteComponents.BadgeText { id: appletNumber // when iconSize < 48, height is always = 24, height / iconSize > 50% // we prefer center aligned badges to top-left aligned ones property bool centerInParent: appletItem.metrics.iconSize < 48 anchors.left: centerInParent? undefined : parent.left anchors.top: centerInParent? undefined : parent.top anchors.centerIn: centerInParent? parent : undefined minimumWidth: 0.4 * (wrapper.zoomScale * appletItem.metrics.iconSize) height: Math.max(24, 0.4 * (wrapper.zoomScale * appletItem.metrics.iconSize)) borderColor: colorizerManager.originalLightTextColor proportion: 0 radiusPerCentage: 100 showNumber: false showText: true textValue: appletNumberLoader.badgeString style3d: root.badges3DStyle } } } diff --git a/containment/package/contents/ui/applet/communicator/Engine.qml b/containment/package/contents/ui/applet/communicator/Engine.qml index 3c42609f..dec60327 100644 --- a/containment/package/contents/ui/applet/communicator/Engine.qml +++ b/containment/package/contents/ui/applet/communicator/Engine.qml @@ -1,126 +1,127 @@ /* * Copyright 2018 Michail Vourlakos * * 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 . */ import QtQuick 2.7 import org.kde.latte.abilities.definitions 0.1 as AbilityDefinition import "../../../code/AppletIdentifier.js" as AppletIdentifier Item{ id: mainCommunicator // ------------------------------------- // BEGIN OF INTERNAL APPLET PROPERTIES // LATTE<->APPLET COMMUNICATION PROTOCOL // ------------------------------------- // // NAME: latteBridge // USAGE: property QtObject latteBridge: null // EXPLANATION: The main shared object that Latte is using to communicate with the applet property bool appletContainsLatteBridge: appletRootItem && appletRootItem.hasOwnProperty("latteBridge") ? true : false //! END OF INTERNAL APPLET PROPERTIES // ------------------------------------- //! BEGIN OF PROPERTIES //this is used for folderView and icon widgets to fake their visual icons readonly property bool canShowOverlaiedLatteIcon: appletIconItem && appletIconItem.visible readonly property bool overlayLatteIconIsActive: canShowOverlaiedLatteIcon && requires.latteIconOverlayEnabled property bool inStartup: true property Item appletRootItem: appletDiscoveredRootItem ? appletDiscoveredRootItem : appletDefaultRootItem property Item appletDiscoveredRootItem: null property Item appletDefaultRootItem: applet && applet.children && applet.children.length>0 ? applet.children[0] : null property Item appletIconItem; //first applet's IconItem to be used by Latte property Item appletImageItem; //first applet's ImageItem to be used by Latte //! END OF PROPERTIES //! BEGIN OF PUBLIC PROPERTIES SET THROUGH LATTEBRIDGE.ACTIONS readonly property Item requires: AbilityDefinition.AppletRequirements{} //! END OF PUBLIC PROPERTIES SET THROUGH LATTEBRIDGE.ACTIONS //! BEGIN OF ABILITIES SUPPORT readonly property bool indexerIsSupported: bridge && bridge.indexer.client + readonly property bool onPositionShortcutsAreSupported: bridge && bridge.shortcuts.client readonly property bool parabolicEffectIsSupported: bridge && bridge.parabolic.client readonly property Item bridge: bridgeLoader.active ? bridgeLoader.item : null //! END OF ABILITIES SUPPORT //! BEGIN OF FUNCTIONS function appletIconItemIsShown() { return appletIconItem && appletIconItem.visible; } function appletImageItemIsShown() { return appletImageItem && appletImageItem.visible; } function reconsiderAppletIconItem() { AppletIdentifier.reconsiderAppletIconItem(); } function setAppletIconItemActive(isActive) { if (appletIconItem) { appletIconItem.active = isActive; } } //! END OF FUNCTIONS //! BEGIN OF CONNECTIONS Connections{ target: appletItem onAppletChanged: { if (applet) { AppletIdentifier.checkAndUpdateAppletRootItem(); AppletIdentifier.reconsiderAppletIconItem(); overlayInitTimer.start(); } } } //! END OF CONNECTIONS //! BEGIN OF LOADERS Loader{ id: bridgeLoader active: appletContainsLatteBridge sourceComponent: LatteBridge{} } //! END OF LOADERS //! BEGIN OF TIMERS //a timer that is used in order to init some Communicator values Timer { id: overlayInitTimer interval: 1000 onTriggered: { AppletIdentifier.checkAndUpdateAppletRootItem(); AppletIdentifier.reconsiderAppletIconItem(); mainCommunicator.inStartup = false; if (root.debugModeTimers) { console.log("containment timer: appletItem fakeInitTimer called..."); } } } //! END OF TIMERS } diff --git a/containment/package/contents/ui/applet/communicator/LatteBridge.qml b/containment/package/contents/ui/applet/communicator/LatteBridge.qml index 5c5f79b9..7ed467a6 100644 --- a/containment/package/contents/ui/applet/communicator/LatteBridge.qml +++ b/containment/package/contents/ui/applet/communicator/LatteBridge.qml @@ -1,156 +1,161 @@ /* * Copyright 2018 Michail Vourlakos * * 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 . */ import QtQuick 2.7 import org.kde.latte.abilities.bridge 0.1 as AbilityBridge Item{ id: settings //! EXPOSED SIGNALS //! USAGE: signals from other applets, , //! EXPLANATION: applets can receive signals from other applets //! to catch signals from other applets in order to communicate with //! each other signal broadcasted(string action, variant value); //! EXPOSED PROPERTIES // NAME: version // USAGE: read-only // EXPLANATION: Latte communication version in order for the applet to use only properties // and parameters that are valid // @since: 0.9 readonly property int version: root.version // NAME: inEditMode // USAGE: read-only // EXPLANATION: Latte sets it to true when this applet is in a Latte containment and Latte // is also in EditMode, that means when the user is altering applets and Latte latteView settings // @since: 0.9 readonly property bool inEditMode: root.inConfigureAppletsMode // NAME: inPlasmaPanelStyle // USAGE: read-only // EXPLANATION: Latte sets it to true when this view behaves as Plasma panel concerning // drawing background shadows externally and applets can take this into account in order // to adjust their appearance and behavior // @since: 0.9 readonly property bool inPlasmaPanelStyle: root.behaveAsPlasmaPanel // NAME: palette // USAGE: read-only // EXPLANATION: Latte updates it to its coloring palette in order for the applet // to take responsibility of its coloring. // USE CASE: when Latte is transparent and applets colors need to be adjusted in order // to look consistent with the underlying desktop background // @since: 0.9 readonly property QtObject palette: !applet.latteSideColoringEnabled ? colorizerManager : null // NAME: applyPalette // USAGE: read-only // EXPLANATION: Latte updates it to TRUE when the applet must use the provided // Latte "palette" and FALSE otherwise // USE CASE: when Latte is transparent and applets colors need to be adjusted in order // to look consistent with the underlying desktop background // @since: 0.9 readonly property bool applyPalette: !applet.latteSideColoringEnabled ? colorizerManager.mustBeShown : false // NAME: parabolicEffectEnabled // USAGE: read-only // EXPLANATION: Parabolic Effect is enabled or not for this Latte View // USE CASE: it can be used from applets that want to be adjusted based // on the parabolic Effect or not // @since: 0.9 readonly property bool parabolicEffectEnabled: root.parabolicEffectEnabled && !appletItem.originalAppletBehavior // NAME: iconSize // USAGE: read-only // EXPLANATION: The current icon size used in the Latte View // USE CASE: it can be used from applets that want their size to be always // relevant to the view icon size // @since: 0.9 readonly property int iconSize: appletItem.metrics.iconSize // NAME: screenEdgeMargin // USAGE: read-only // EXPLANATION: The screen edge margin applied in pixels // USE CASE: it can be used from applets that want to be informed what is the screen edge margin // currently applied // @since: 0.10 readonly property int screenEdgeMargin: appletItem.metrics.margin.screenEdge // NAME: maxZoomFactor // USAGE: read-only // EXPLANATION: The maximum zoom factor currently used // USE CASE: it can be used from applets that want to be informed what is the maximum // zoom factor currently used // @since: 0.9 readonly property real maxZoomFactor: appletItem.parabolic.factor.zoom // NAME: windowsTracker // USAGE: read-only // EXPLANATION: windows tracking based on the view this applet is present // USE CASE: it can be used from applets that want windows tracking in order // to update their appearance or their behavior accordingly // @since: 0.9 readonly property QtObject windowsTracker: applet.windowsTrackingEnabled && latteView && latteView.windowsTracker ? latteView.windowsTracker : null readonly property Item actions: Actions{} readonly property Item applet: mainCommunicator.requires readonly property Item animations: appletItem.animations.publicApi readonly property Item metrics: appletItem.metrics.publicApi readonly property AbilityBridge.Indexer indexer: AbilityBridge.Indexer { host: appletItem.indexer appletIndex: index headAppletIsSeparator: appletItem.headAppletIsSeparator tailAppletIsSeparator: appletItem.tailAppletIsSeparator } readonly property AbilityBridge.ParabolicEffect parabolic: AbilityBridge.ParabolicEffect { host: appletItem.parabolic appletIndex: index } + readonly property AbilityBridge.PositionShortcuts shortcuts: AbilityBridge.PositionShortcuts { + host: appletItem.shortcuts + appletIndex: index + } + Connections { target: root onBroadcastedToApplet: { if (appletItem.applet && appletItem.applet.pluginName === pluginName) { settings.broadcasted(action, value); } } } //! Initialize Component.onCompleted: { if (appletContainsLatteBridge) { appletRootItem.latteBridge = settings; } } Component.onDestruction: { if (appletContainsLatteBridge) { appletRootItem.latteBridge = null; } } } diff --git a/containment/package/contents/ui/main.qml b/containment/package/contents/ui/main.qml index 314cb023..3d9ceec9 100644 --- a/containment/package/contents/ui/main.qml +++ b/containment/package/contents/ui/main.qml @@ -1,1594 +1,1600 @@ /* * Copyright 2016 Smith AR * Michail Vourlakos * * 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 . */ import QtQuick 2.8 import QtQuick.Layouts 1.1 import QtQuick.Window 2.2 import QtGraphicalEffects 1.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.kquickcontrolsaddons 2.0 import org.kde.plasma.plasmoid 2.0 import org.kde.latte.core 0.2 as LatteCore import org.kde.latte.components 1.0 as LatteComponents import org.kde.latte.private.app 0.1 as LatteApp import org.kde.latte.private.containment 0.1 as LatteContainment import "abilities" as Ability import "applet" as Applet import "colorizer" as Colorizer import "editmode" as EditMode import "indicators" as Indicators import "layouts" as Layouts import "./background" as Background import "./debug" as Debug import "../code/LayoutManager.js" as LayoutManager Item { id: root objectName: "containmentViewLayout" LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft && !root.isVertical LayoutMirroring.childrenInherit: true //// BEGIN SIGNALS signal destroyInternalViewSplitters(); signal emptyAreasWheel(QtObject wheel); signal separatorsUpdated(); signal updateEffectsArea(); signal updateIndexes(); signal broadcastedToApplet(string pluginName, string action, variant value); //// END SIGNALS ////BEGIN properties property bool debugMode: Qt.application.arguments.indexOf("--graphics")>=0 property bool debugModeLayouter: Qt.application.arguments.indexOf("--layouter")>=0 property bool debugModeLocalGeometry: Qt.application.arguments.indexOf("--localgeometry")>=0 property bool debugModeSpacers: Qt.application.arguments.indexOf("--spacers")>=0 property bool debugModeTimers: Qt.application.arguments.indexOf("--timers")>=0 property bool debugModeWindow: Qt.application.arguments.indexOf("--with-window")>=0 property bool debugModeOverloadedIcons: Qt.application.arguments.indexOf("--overloaded-icons")>=0 readonly property int version: LatteCore.Environment.makeVersion(0,9,4) property bool addLaunchersMessage: false property bool addLaunchersInTaskManager: plasmoid.configuration.addLaunchersInTaskManager property bool backgroundOnlyOnMaximized: plasmoid.configuration.backgroundOnlyOnMaximized property bool behaveAsPlasmaPanel: { if (!LatteCore.WindowSystem.compositingActive) { //! In NOCOMPOSITING mode VIEWS should behave as real windows and that way //! we gain also the snapping features from KWin return true; } if (!latteView || !latteView.visibility) { return false; } if (screenEdgeMarginEnabled && plasmoid.configuration.fittsLawIsRequested) { //! dont use when floating views are requesting Fitt's Law return false; } var staticLayout = (plasmoid.configuration.minLength === plasmoid.configuration.maxLength); return (visibilityManager.panelIsBiggerFromIconSize && (parabolic.factor.maxZoom === 1.0) && (plasmoid.configuration.alignment === LatteCore.Types.Justify || staticLayout) && !root.editMode && !visibilityManager.inLocationAnimation); } readonly property bool behaveAsDockWithMask: !behaveAsPlasmaPanel readonly property bool viewIsAvailable: latteView && latteView.visibility && latteView.effects property int viewType: { var staticLayout = (plasmoid.configuration.minLength === plasmoid.configuration.maxLength); if ((plasmoid.configuration.alignment === LatteCore.Types.Justify || staticLayout) && (plasmoid.configuration.useThemePanel) && (plasmoid.configuration.panelSize === 100) && (parabolic.factor.maxZoom === 1.0)) { return LatteCore.Types.PanelView; } return LatteCore.Types.DockView; } property bool blurEnabled: plasmoid.configuration.blurEnabled && (!forceTransparentPanel || forcePanelForBusyBackground) readonly property bool ignoreRegularFilesDragging: !root.editMode && (dragInfo.computationsAreValid || foreDropArea.dragInfo.computationsAreValid) && !root.dragInfo.isPlasmoid && !root.dragInfo.onlyLaunchers readonly property Item dragInfo: Item { property bool entered: backDropArea.dragInfo.entered || foreDropArea.dragInfo.entered property bool isTask: backDropArea.dragInfo.isTask || foreDropArea.dragInfo.isTask property bool isPlasmoid: backDropArea.dragInfo.isPlasmoid || foreDropArea.dragInfo.isPlasmoid property bool isSeparator: backDropArea.dragInfo.isSeparator || foreDropArea.dragInfo.isSeparator property bool isLatteTasks: backDropArea.dragInfo.isLatteTasks || foreDropArea.dragInfo.isLatteTasks property bool onlyLaunchers: backDropArea.dragInfo.onlyLaunchers || foreDropArea.dragInfo.onlyLaunchers // onIsPlasmoidChanged: console.log("isPlasmoid :: " + backDropArea.dragInfo.isPlasmoid + " _ " + foreDropArea.dragInfo.isPlasmoid ); // onEnteredChanged: console.log("entered :: " + backDropArea.dragInfo.entered + " _ " + foreDropArea.dragInfo.entered ); } property bool containsOnlyPlasmaTasks: latteView ? latteView.extendedInterface.hasPlasmaTasks && !latteView.extendedInterface.hasLatteTasks : false property bool dockContainsMouse: latteView && latteView.visibility ? latteView.visibility.containsMouse : false property bool disablePanelShadowMaximized: plasmoid.configuration.disablePanelShadowForMaximized && LatteCore.WindowSystem.compositingActive property bool drawShadowsExternal: panelShadowsActive && behaveAsPlasmaPanel && !visibilityManager.inTempHiding property bool editMode: editModeVisual.inEditMode property bool windowIsTouching: latteView && latteView.windowsTracker && (latteView.windowsTracker.currentScreen.activeWindowTouching || latteView.windowsTracker.currentScreen.activeWindowTouchingEdge || hasExpandedApplet) property bool forceSolidPanel: (latteView && latteView.visibility && LatteCore.WindowSystem.compositingActive && !inConfigureAppletsMode && userShowPanelBackground && ( (plasmoid.configuration.solidBackgroundForMaximized && !(hasExpandedApplet && !plasmaBackgroundForPopups) && (latteView.windowsTracker.currentScreen.existsWindowTouching || latteView.windowsTracker.currentScreen.existsWindowTouchingEdge)) || (hasExpandedApplet && plasmaBackgroundForPopups) )) || solidBusyForTouchingBusyVerticalView || plasmaStyleBusyForTouchingBusyVerticalView || !LatteCore.WindowSystem.compositingActive property bool forceTransparentPanel: root.backgroundOnlyOnMaximized && latteView && latteView.visibility && LatteCore.WindowSystem.compositingActive && !inConfigureAppletsMode && !forceSolidPanel && !(latteView.windowsTracker.currentScreen.existsWindowTouching || latteView.windowsTracker.currentScreen.existsWindowTouchingEdge) && !(windowColors === LatteContainment.Types.ActiveWindowColors && selectedWindowsTracker.existsWindowActive) property bool forcePanelForBusyBackground: userShowPanelBackground && (root.themeColors === LatteContainment.Types.SmartThemeColors) && ( (root.forceTransparentPanel && colorizerManager.backgroundIsBusy) || normalBusyForTouchingBusyVerticalView ) property bool normalBusyForTouchingBusyVerticalView: (latteView && latteView.windowsTracker /*is touching a vertical view that is in busy state and the user prefers isBusy transparency*/ && latteView.windowsTracker.currentScreen.isTouchingBusyVerticalView && root.themeColors === LatteContainment.Types.SmartThemeColors && plasmoid.configuration.backgroundOnlyOnMaximized /*&& !plasmoid.configuration.solidBackgroundForMaximized && !plasmaBackgroundForPopups*/) property bool solidBusyForTouchingBusyVerticalView: false //DISABLED, until to check if the normalBusyForTouchingBusyVerticalView is enough to catch and handle the case /*(latteView && latteView.windowsTracker /*is touching a vertical view that is in busy state and the user prefers solidness*/ /* && latteView.windowsTracker.currentScreen.isTouchingBusyVerticalView && root.themeColors === LatteContainment.Types.SmartThemeColors && plasmoid.configuration.backgroundOnlyOnMaximized && plasmoid.configuration.solidBackgroundForMaximized && !plasmaBackgroundForPopups)*/ property bool plasmaStyleBusyForTouchingBusyVerticalView: false //DISABLED, until to check if the normalBusyForTouchingBusyVerticalView is enough to catch and handle the case //(latteView && latteView.windowsTracker /*is touching a vertical view that is in busy state and the user prefers solidness*/ /* && latteView.windowsTracker.currentScreen.isTouchingBusyVerticalView && root.themeColors === LatteContainment.Types.SmartThemeColors && plasmoid.configuration.backgroundOnlyOnMaximized && plasmaBackgroundForPopups)*/ property bool hideThickScreenGap: screenEdgeMarginEnabled && plasmoid.configuration.hideScreenGapForMaximized && latteView && latteView.windowsTracker && latteView.windowsTracker.currentScreen.existsWindowMaximized property bool hideLengthScreenGaps: hideThickScreenGap && (latteView.visibility.mode === LatteCore.Types.AlwaysVisible || latteView.visibility.mode === LatteCore.Types.WindowsGoBelow) && (plasmoid.configuration.alignment === LatteCore.Types.Justify) && plasmoid.configuration.maxLength>85 && !root.editMode property int themeColors: plasmoid.configuration.themeColors property int windowColors: plasmoid.configuration.windowColors property bool colorizerEnabled: themeColors !== LatteContainment.Types.PlasmaThemeColors || windowColors !== LatteContainment.Types.NoneWindowColors property bool plasmaBackgroundForPopups: plasmoid.configuration.plasmaBackgroundForPopups readonly property bool hasExpandedApplet: latteView && latteView.extendedInterface.hasExpandedApplet; readonly property bool hasUserSpecifiedBackground: (latteView && latteView.layout && latteView.layout.background.startsWith("/")) ? true : false readonly property bool inConfigureAppletsMode: root.editMode && (plasmoid.configuration.inConfigureAppletsMode || !LatteCore.WindowSystem.compositingActive) readonly property bool parabolicEffectEnabled: parabolic.factor.zoom>1 && !inConfigureAppletsMode property bool dockIsShownCompletely: !(dockIsHidden || inSlidingIn || inSlidingOut) && !root.editMode property bool closeActiveWindowEnabled: plasmoid.configuration.closeActiveWindowEnabled property bool dragActiveWindowEnabled: plasmoid.configuration.dragActiveWindowEnabled property bool immutable: plasmoid.immutable property bool inFullJustify: (plasmoid.configuration.alignment === LatteCore.Types.Justify) && (maxLengthPerCentage===100) property bool inSlidingIn: visibilityManager ? visibilityManager.inSlidingIn : false property bool inSlidingOut: visibilityManager ? visibilityManager.inSlidingOut : false property bool inStartup: true property bool isHalfShown: false //is used to disable the zoom hovering effect at sliding in-out the dock property bool isHorizontal: plasmoid.formFactor === PlasmaCore.Types.Horizontal property bool isReady: !(dockIsHidden || inSlidingIn || inSlidingOut) property bool isVertical: !isHorizontal property bool mouseWheelActions: plasmoid.configuration.mouseWheelActions property bool onlyAddingStarup: true //is used for the initialization phase in startup where there aren't removals, this variable provides a way to grow icon size property bool shrinkThickMargins: plasmoid.configuration.shrinkThickMargins //FIXME: possibly this is going to be the default behavior, this user choice //has been dropped from the Dock Configuration Window //property bool smallAutomaticIconJumps: plasmoid.configuration.smallAutomaticIconJumps property bool smallAutomaticIconJumps: true property bool userShowPanelBackground: LatteCore.WindowSystem.compositingActive ? plasmoid.configuration.useThemePanel : true property bool useThemePanel: noApplets === 0 || !LatteCore.WindowSystem.compositingActive ? true : (plasmoid.configuration.useThemePanel || plasmoid.configuration.solidBackgroundForMaximized) property bool plasma515: LatteCore.Environment.plasmaDesktopVersion >= LatteCore.Environment.makeVersion(5,15,0) property bool plasma518: LatteCore.Environment.plasmaDesktopVersion >= LatteCore.Environment.makeVersion(5,18,0) readonly property int minAppletLengthInConfigure: 16 readonly property int maxJustifySplitterSize: 64 property int latteAppletPos: -1 property real minLengthPerCentage: plasmoid.configuration.minLength property real maxLengthPerCentage: hideLengthScreenGaps ? 100 : plasmoid.configuration.maxLength property int minLength: { if (root.panelAlignment === LatteCore.Types.Justify) { return maxLength; } if (root.isHorizontal) { return behaveAsPlasmaPanel && LatteCore.WindowSystem.compositingActive ? width : width * (minLengthPerCentage/100) } else { return behaveAsPlasmaPanel && LatteCore.WindowSystem.compositingActive ? height : height * (minLengthPerCentage/100) } } property int maxLength: { if (root.isHorizontal) { return behaveAsPlasmaPanel ? width : width * (maxLengthPerCentage/100) } else { return behaveAsPlasmaPanel ? height : height * (maxLengthPerCentage/100) } } property int scrollAction: plasmoid.configuration.scrollAction property bool panelOutline: plasmoid.configuration.panelOutline property int panelEdgeSpacing: Math.max(background.lengthMargins, 1.5*appShadowSize) property int panelTransparency: plasmoid.configuration.panelTransparency //user set property bool panelShadowsActive: { if (!userShowPanelBackground) { return false; } if (inConfigureAppletsMode) { return plasmoid.configuration.panelShadows; } var forcedNoShadows = (plasmoid.configuration.panelShadows && disablePanelShadowMaximized && latteView && latteView.windowsTracker && latteView.windowsTracker.currentScreen.activeWindowMaximized); if (forcedNoShadows) { return false; } var transparencyCheck = (blurEnabled || (!blurEnabled && background.currentOpacity>20)); //! Draw shadows for isBusy state only when current panelTransparency is greater than 10% if (plasmoid.configuration.panelShadows && root.forcePanelForBusyBackground && transparencyCheck) { return true; } if (( (plasmoid.configuration.panelShadows && !root.backgroundOnlyOnMaximized) || (plasmoid.configuration.panelShadows && root.backgroundOnlyOnMaximized && !root.forceTransparentPanel)) && !forcedNoShadows) { return true; } if (hasExpandedApplet && plasmaBackgroundForPopups) { return true; } return false; } property int appShadowOpacity: (plasmoid.configuration.shadowOpacity/100) * 255 property int appShadowSize: enableShadows ? (0.5*metrics.iconSize) * (plasmoid.configuration.shadowSize/100) : 0 property int appShadowSizeOriginal: enableShadows ? (0.5*metrics.maxIconSize) * (plasmoid.configuration.shadowSize/100) : 0 property string appChosenShadowColor: { if (plasmoid.configuration.shadowColorType === LatteContainment.Types.ThemeColorShadow) { var strC = String(theme.textColor); return strC.indexOf("#") === 0 ? strC.substr(1) : strC; } else if (plasmoid.configuration.shadowColorType === LatteContainment.Types.UserColorShadow) { return plasmoid.configuration.shadowColor; } // default shadow color return "080808"; } property string appShadowColor: "#" + decimalToHex(appShadowOpacity) + appChosenShadowColor property string appShadowColorSolid: "#" + appChosenShadowColor property int offset: { if (behaveAsPlasmaPanel) { return 0; } if (root.isHorizontal) { return width * (plasmoid.configuration.offset/100); } else { height * (plasmoid.configuration.offset/100) } } property int editShadow: { if (!LatteCore.WindowSystem.compositingActive) { return 0; } else if (latteView && latteView.screenGeometry) { return latteView.screenGeometry.height/90; } else { return 7; } } property bool screenEdgeMarginEnabled: plasmoid.configuration.screenEdgeMargin >= 0 && !plasmoid.configuration.shrinkThickMargins property int widthMargins: root.isVertical ? metrics.totals.thicknessEdges : metrics.totals.lengthEdges property int heightMargins: root.isHorizontal ? metrics.totals.thicknessEdges : metrics.totals.lengthEdges property int panelAlignment: plasmoid.configuration.alignment readonly property string plasmoidName: "org.kde.latte.plasmoid" property var badgesForActivate: { if (!shortcutsEngine) { return ['1','2','3','4','5','6','7','8','9','0', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.']; } return shortcutsEngine.badgesForActivate; } property var iconsArray: [16, 22, 32, 48, 64, 96, 128, 256] property Item dragOverlay property Item toolBox property Item latteAppletContainer property Item latteApplet readonly property alias animations: _animations readonly property alias background: _background readonly property alias autosize: _autosize readonly property alias indexer: _indexer readonly property alias indicatorsManager: indicators readonly property alias layouter: _layouter readonly property alias metrics: _metrics readonly property alias parabolic: _parabolic readonly property alias parabolicManager: _parabolicManager readonly property alias maskManager: visibilityManager readonly property alias layoutsContainerItem: layoutsContainer readonly property alias latteView: _interfaces.view readonly property alias layoutsManager: _interfaces.layoutsManager readonly property alias shortcutsEngine: _interfaces.globalShortcuts readonly property alias themeExtended: _interfaces.themeExtended readonly property alias universalSettings: _interfaces.universalSettings readonly property QtObject viewLayout: latteView && latteView.layout ? latteView.layout : null readonly property QtObject selectedWindowsTracker: { if (latteView && latteView.windowsTracker) { switch(plasmoid.configuration.activeWindowFilter) { case LatteContainment.Types.ActiveInCurrentScreen: return latteView.windowsTracker.currentScreen; case LatteContainment.Types.ActiveFromAllScreens: return latteView.windowsTracker.allScreens; } } return null; } // TO BE DELETED, if not needed: property int counter:0; ///BEGIN properties provided to Latte Plasmoid //shadows for applets, it should be removed as the appleitems don't need it any more property bool badges3DStyle: universalSettings ? universalSettings.badges3DStyle : true property bool enableShadows: plasmoid.configuration.appletShadowsEnabled property bool dockIsHidden: latteView && latteView.visibility ? latteView.visibility.isHidden : true property bool titleTooltips: plasmoid.configuration.titleTooltips property int tasksCount: latteApplet ? latteApplet.tasksCount : 0 property rect screenGeometry: latteView ? latteView.screenGeometry : plasmoid.screenGeometry readonly property color minimizedDotColor: colorizerManager.minimizedDotColor ///END properties from latteApplet Plasmoid.backgroundHints: PlasmaCore.Types.NoBackground //// BEGIN properties in functions property int noApplets: { var count1 = 0; var count2 = 0; count1 = layoutsContainer.mainLayout.children.length; var tempLength = layoutsContainer.mainLayout.children.length; for (var i=tempLength-1; i>=0; --i) { var applet = layoutsContainer.mainLayout.children[i]; if (applet && (applet === dndSpacer || applet === lastSpacer || applet.isInternalViewSplitter)) count1--; } count2 = layoutsContainer.endLayout.children.length; tempLength = layoutsContainer.endLayout.children.length; for (var i=tempLength-1; i>=0; --i) { var applet = layoutsContainer.endLayout.children[i]; if (applet && (applet === dndSpacer || applet === lastSpacer || applet.isInternalViewSplitter)) count2--; } return (count1 + count2); } ///The index of user's current icon size property int currentIconIndex:{ for(var i=iconsArray.length-1; i>=0; --i){ if(iconsArray[i] === metrics.iconSize){ return i; } } return 3; } //// END properties in functions ////////////////END properties //// BEGIN OF Behaviors Behavior on offset { enabled: editModeVisual.editAnimationInFullThickness NumberAnimation { id: offsetAnimation duration: 0.8 * animations.duration.proposed easing.type: Easing.OutCubic } } //// END OF Behaviors //////////////START OF CONNECTIONS onEditModeChanged: { if (!editMode) { layouter.updateSizeForAppletsInFill(); } //! This is used in case the dndspacer has been left behind //! e.g. the user drops a folder and a context menu is appearing //! but the user decides to not make a choice for the applet type if (dndSpacer.parent !== root) { dndSpacer.parent = root; } } onInConfigureAppletsModeChanged: { updateIndexes(); } //! It is used only when the user chooses different alignment types //! and not during startup onPanelAlignmentChanged: { if (!root.editMode) { return; } if (root.editMode/*!inConfigureAppletsMode*/){ if (panelAlignment===LatteCore.Types.Justify) { addInternalViewSplitters(); splitMainLayoutToLayouts(); } else { joinLayoutsToMainLayout(); root.destroyInternalViewSplitters(); } } LayoutManager.save(); updateIndexes(); } onLatteViewChanged: { if (latteView) { if (latteView.positioner) { latteView.positioner.hideDockDuringLocationChangeStarted.connect(visibilityManager.slotHideDockDuringLocationChange); latteView.positioner.showDockAfterLocationChangeFinished.connect(visibilityManager.slotShowDockAfterLocationChange); latteView.positioner.hideDockDuringScreenChangeStarted.connect(visibilityManager.slotHideDockDuringLocationChange); latteView.positioner.showDockAfterScreenChangeFinished.connect(visibilityManager.slotShowDockAfterLocationChange); latteView.positioner.hideDockDuringMovingToLayoutStarted.connect(visibilityManager.slotHideDockDuringLocationChange); latteView.positioner.showDockAfterMovingToLayoutFinished.connect(visibilityManager.slotShowDockAfterLocationChange); } if (latteView.visibility) { latteView.visibility.onContainsMouseChanged.connect(visibilityManager.slotContainsMouseChanged); latteView.visibility.onMustBeHide.connect(visibilityManager.slotMustBeHide); latteView.visibility.onMustBeShown.connect(visibilityManager.slotMustBeShown); } } } Connections { target: latteView onPositionerChanged: { if (latteView.positioner) { latteView.positioner.hideDockDuringLocationChangeStarted.connect(visibilityManager.slotHideDockDuringLocationChange); latteView.positioner.showDockAfterLocationChangeFinished.connect(visibilityManager.slotShowDockAfterLocationChange); latteView.positioner.hideDockDuringScreenChangeStarted.connect(visibilityManager.slotHideDockDuringLocationChange); latteView.positioner.showDockAfterScreenChangeFinished.connect(visibilityManager.slotShowDockAfterLocationChange); latteView.positioner.hideDockDuringMovingToLayoutStarted.connect(visibilityManager.slotHideDockDuringLocationChange); latteView.positioner.showDockAfterMovingToLayoutFinished.connect(visibilityManager.slotShowDockAfterLocationChange); } } onVisibilityChanged: { if (latteView.visibility) { latteView.visibility.onContainsMouseChanged.connect(visibilityManager.slotContainsMouseChanged); latteView.visibility.onMustBeHide.connect(visibilityManager.slotMustBeHide); latteView.visibility.onMustBeShown.connect(visibilityManager.slotMustBeShown); } } } onMaxLengthChanged: { layouter.updateSizeForAppletsInFill(); } onToolBoxChanged: { if (toolBox) { toolBox.visible = false; } } onIsReadyChanged: { if (isReady && !titleTooltipDialog.visible && titleTooltipDialog.activeItemHovered){ titleTooltipDialog.show(titleTooltipDialog.activeItem, titleTooltipDialog.activeItemText); } } onIsVerticalChanged: { if (isVertical) { if (plasmoid.configuration.alignment === LatteCore.Types.Left) plasmoid.configuration.alignment = LatteCore.Types.Top; else if (plasmoid.configuration.alignment === LatteCore.Types.Right) plasmoid.configuration.alignment = LatteCore.Types.Bottom; } else { if (plasmoid.configuration.alignment === LatteCore.Types.Top) plasmoid.configuration.alignment = LatteCore.Types.Left; else if (plasmoid.configuration.alignment === LatteCore.Types.Bottom) plasmoid.configuration.alignment = LatteCore.Types.Right; } } Component.onCompleted: { // currentLayout.isLayoutHorizontal = isHorizontal LayoutManager.plasmoid = plasmoid; LayoutManager.root = root; LayoutManager.layout = layoutsContainer.mainLayout; LayoutManager.layoutS = layoutsContainer.startLayout; LayoutManager.layoutE = layoutsContainer.endLayout; LayoutManager.lastSpacer = lastSpacer; LayoutManager.metrics = metrics; upgrader_v010_alignment(); LayoutManager.restore(); plasmoid.action("configure").visible = !plasmoid.immutable; plasmoid.action("configure").enabled = !plasmoid.immutable; inStartupTimer.start(); } Component.onDestruction: { console.debug("Destroying Latte Dock Containment ui..."); layouter.appletsInParentChange = true; if (latteView) { if (latteView.positioner) { latteView.positioner.hideDockDuringLocationChangeStarted.disconnect(visibilityManager.slotHideDockDuringLocationChange); latteView.positioner.showDockAfterLocationChangeFinished.disconnect(visibilityManager.slotShowDockAfterLocationChange); latteView.positioner.hideDockDuringScreenChangeStarted.disconnect(visibilityManager.slotHideDockDuringLocationChange); latteView.positioner.showDockAfterScreenChangeFinished.disconnect(visibilityManager.slotShowDockAfterLocationChange); latteView.positioner.hideDockDuringMovingToLayoutStarted.disconnect(visibilityManager.slotHideDockDuringLocationChange); latteView.positioner.showDockAfterMovingToLayoutFinished.disconnect(visibilityManager.slotShowDockAfterLocationChange); } if (latteView.visibility) { latteView.visibility.onContainsMouseChanged.disconnect(visibilityManager.slotContainsMouseChanged); latteView.visibility.onMustBeHide.disconnect(visibilityManager.slotMustBeHide); latteView.visibility.onMustBeShown.disconnect(visibilityManager.slotMustBeShown); } } } Containment.onAppletAdded: { addApplet(applet, x, y); console.log(applet.pluginName); LayoutManager.save(); updateIndexes(); } Containment.onAppletRemoved: { LayoutManager.removeApplet(applet); var flexibleFound = false; for (var i = 0; i < layoutsContainer.mainLayout.children.length; ++i) { var applet = layoutsContainer.mainLayout.children[i].applet; if (applet && ((root.isHorizontal && applet.Layout.fillWidth) || (!root.isHorizontal && applet.Layout.fillHeight)) && applet.visible) { flexibleFound = true; break } } if (!flexibleFound) { lastSpacer.parent = layoutsContainer.mainLayout; } LayoutManager.save(); updateIndexes(); } Plasmoid.onUserConfiguringChanged: { if (plasmoid.immutable) { if (dragOverlay) { dragOverlay.destroy(); } return; } // console.debug("user configuring", plasmoid.userConfiguring) if (plasmoid.userConfiguring) { // console.log("applets------"); for (var i = 0; i < plasmoid.applets.length; ++i) { // console.log("applet:"+i); plasmoid.applets[i].expanded = false; } if (!dragOverlay) { var component = Qt.createComponent("editmode/ConfigOverlay.qml"); if (component.status == Component.Ready) { dragOverlay = component.createObject(root); } else { console.log("Could not create ConfigOverlay"); console.log(component.errorString()); } component.destroy(); } else { dragOverlay.visible = true; } } else { if (dragOverlay) { dragOverlay.visible = false; dragOverlay.destroy(); } } } Plasmoid.onImmutableChanged: { plasmoid.action("configure").visible = !plasmoid.immutable; plasmoid.action("configure").enabled = !plasmoid.immutable; ///Set Preferred Sizes/// ///Notice: they are set here because if they are set with a binding ///they break the !immutable experience, the latteView becomes too small ///to add applets /* if (plasmoid.immutable) { if(root.isHorizontal) { root.Layout.preferredWidth = (plasmoid.configuration.alignment === LatteCore.Types.Justify ? layoutsContainer.width + 0.5*iconMargin : layoutsContainer.mainLayout.width + iconMargin); } else { root.Layout.preferredHeight = (plasmoid.configuration.alignment === LatteCore.Types.Justify ? layoutsContainer.height + 0.5*iconMargin : layoutsContainer.mainLayout.height + iconMargin); } } else { if (root.isHorizontal) { root.Layout.preferredWidth = Screen.width; } else { root.Layout.preferredHeight = Screen.height; } }*/ visibilityManager.updateMaskArea(); } //////////////END OF CONNECTIONS //////////////START OF FUNCTIONS function addApplet(applet, x, y) { var container = appletContainerComponent.createObject(dndSpacer.parent) container.applet = applet; applet.parent = container.appletWrapper; applet.anchors.fill = container.appletWrapper; applet.visible = true; // don't show applet if it chooses to be hidden but still make it // accessible in the panelcontroller container.visible = Qt.binding(function() { return applet.status !== PlasmaCore.Types.HiddenStatus || (!plasmoid.immutable && root.inConfigureAppletsMode) }) addContainerInLayout(container, applet, x, y); } function addContainerInLayout(container, applet, x, y){ // Is there a DND placeholder? Replace it! if ( (dndSpacer.parent === layoutsContainer.mainLayout) || (dndSpacer.parent === layoutsContainer.startLayout) || (dndSpacer.parent===layoutsContainer.endLayout)) { LayoutManager.insertBeforeForLayout(dndSpacer.parent, dndSpacer, container); dndSpacer.parent = root; return; // If the provided position is valid, use it. } else if (x >= 0 && y >= 0) { var index = LayoutManager.insertAtCoordinates2(container, x , y); // Fall through to determining an appropriate insert position. } else { var before = null; container.animationsEnabled = false; if (lastSpacer.parent === layoutsContainer.mainLayout) { before = lastSpacer; } // Insert icons to the left of whatever is at the center (usually a Task Manager), // if it exists. // FIXME TODO: This is a real-world fix to produce a sensible initial position for // launcher icons added by launcher menu applets. The basic approach has been used // since Plasma 1. However, "add launcher to X" is a generic-enough concept and // frequent-enough occurrence that we'd like to abstract it further in the future // and get rid of the ugliness of parties external to the containment adding applets // of a specific type, and the containment caring about the applet type. In a better // system the containment would be informed of requested launchers, and determine by // itself what it wants to do with that information. if (applet.pluginName == "org.kde.plasma.icon") { var middle = layoutsContainer.mainLayout.childAt(root.width / 2, root.height / 2); if (middle) { before = middle; } // Otherwise if lastSpacer is here, enqueue before it. } if (before) { LayoutManager.insertBefore(before, container); // Fall through to adding at the end. } else { container.parent = layoutsContainer.mainLayout; } } //Important, removes the first children of the layoutsContainer.mainLayout after the first //applet has been added lastSpacer.parent = root; updateIndexes(); } function addInternalViewSplitters(){ if (internalViewSplittersCount() === 0) { addInternalViewSplitter(plasmoid.configuration.splitterPosition); addInternalViewSplitter(plasmoid.configuration.splitterPosition2); } } function addInternalViewSplitter(pos){ var splittersCount = internalViewSplittersCount(); if(splittersCount<2){ var container = appletContainerComponent.createObject(root); container.internalSplitterId = splittersCount+1; container.visible = true; if(pos>=0 ){ LayoutManager.insertAtIndex(layoutsContainer.mainLayout, container, pos); } else { LayoutManager.insertAtIndex(layoutsContainer.mainLayout, container, Math.floor(layouter.mainLayout.count / 2)); } } } //! it is used in order to check the right click position //! the only way to take into account the visual appearance //! of the applet (including its spacers) function appletContainsPos(appletId, pos){ for (var i = 0; i < layoutsContainer.startLayout.children.length; ++i) { var child = layoutsContainer.startLayout.children[i]; if (child && child.applet && child.applet.id === appletId && child.containsPos(pos)) return true; } for (var i = 0; i < layoutsContainer.mainLayout.children.length; ++i) { var child = layoutsContainer.mainLayout.children[i]; if (child && child.applet && child.applet.id === appletId && child.containsPos(pos)) return true; } for (var i = 0; i < layoutsContainer.endLayout.children.length; ++i) { var child = layoutsContainer.endLayout.children[i]; if (child && child.applet && child.applet.id === appletId && child.containsPos(pos)) return true; } return false; } function checkLastSpacer() { lastSpacer.parent = root var expands = false; if (isHorizontal) { for (var container in layoutsContainer.mainLayout.children) { var item = layoutsContainer.mainLayout.children[container]; if (item.Layout && item.Layout.fillWidth) { expands = true; } } } else { for (var container in layoutsContainer.mainLayout.children) { var item = layoutsContainer.mainLayout.children[container]; if (item.Layout && item.Layout.fillHeight) { expands = true; } } } if (!expands) { lastSpacer.parent = layoutsContainer.mainLayout } } function containmentActions(){ return latteView.containmentActions(); } function decimalToHex(d, padding) { var hex = Number(d).toString(16); padding = typeof (padding) === "undefined" || padding === null ? padding = 2 : padding; while (hex.length < padding) { hex = "0" + hex; } return hex; } function internalViewSplittersCount(){ var splitters = 0; for (var container in layoutsContainer.startLayout.children) { var item = layoutsContainer.startLayout.children[container]; if(item && item.isInternalViewSplitter) { splitters = splitters + 1; } } for (var container in layoutsContainer.mainLayout.children) { var item = layoutsContainer.mainLayout.children[container]; if(item && item.isInternalViewSplitter) { splitters = splitters + 1; } } for (var container in layoutsContainer.endLayout.children) { var item = layoutsContainer.endLayout.children[container]; if(item && item.isInternalViewSplitter) { splitters = splitters + 1; } } return splitters; } function layoutManager() { return LayoutManager; } function layoutManagerInsertBefore(place, item) { LayoutManager.insertBefore(place, item); } function layoutManagerInsertAfter(place, item) { LayoutManager.insertAfter(place, item); } function layoutManagerSave() { LayoutManager.save(); } function layoutManagerSaveOptions() { LayoutManager.saveOptions(); } function mouseInCanBeHoveredApplet(){ var applets = layoutsContainer.startLayout.children; for(var i=0; i=0; --i){ if(iconsArray[i] === size){ return true; } } return false; } function slotPreviewsShown(){ if (latteView) { latteView.extendedInterface.deactivateApplets(); } } function layoutManagerMoveAppletsBasedOnJustifyAlignment() { if (plasmoid.configuration.alignment !== 10) { return; } layouter.appletsInParentChange = true; var splitter = -1; var startChildrenLength = layoutsContainer.startLayout.children.length; //! Check if there is a splitter inside start layout after the user was dragging its applets for (var i=0; i=0) { for (var i=startChildrenLength-1; i>=splitter; --i){ var item = layoutsContainer.startLayout.children[i]; LayoutManager.insertAtIndex(layoutsContainer.mainLayout, item, 0); } } var splitter2 = -1; var endChildrenLength = layoutsContainer.endLayout.children.length; //! Check if there is a splitter inside endlayout after the user was dragging its applets for (var i=0; i=0) { for (var i=0; i<=splitter2; ++i){ var item = layoutsContainer.endLayout.children[0]; item.parent = layoutsContainer.mainLayout; } } //! Validate applets positioning and move applets out of splitters to start/endlayouts accordingly splitMainLayoutToLayouts(); layouter.appletsInParentChange = false; } function splitMainLayoutToLayouts() { if (internalViewSplittersCount() === 2) { layouter.appletsInParentChange = true; console.log("LAYOUTS: Moving applets from MAIN to THREE Layouts mode..."); var splitter = -1; var splitter2 = -1; var totalChildren = layoutsContainer.mainLayout.children.length; for (var i=0; i=0 && splitter2 === -1) { splitter2 = i; } } // console.log("update layouts 1:"+splitter + " - "+splitter2); if (splitter > 0) { for (var i=0; i 0) { splitter2 = splitter2 - splitter; // console.log("update layouts 2:"+splitter + " - "+splitter2); totalChildren = layoutsContainer.mainLayout.children.length; for (var i=totalChildren-1; i>=splitter2+1; --i){ var item = layoutsContainer.mainLayout.children[i]; LayoutManager.insertAtIndex(layoutsContainer.endLayout, item, 0); } } layouter.appletsInParentChange = false; } } function joinLayoutsToMainLayout() { layouter.appletsInParentChange = true; console.log("LAYOUTS: Moving applets from THREE to MAIN Layout mode..."); var totalChildren1 = layoutsContainer.mainLayout.children.length; for (var i=totalChildren1-1; i>=0; --i) { var item1 = layoutsContainer.mainLayout.children[0]; item1.parent = layoutsContainer.startLayout; } var totalChildren2 = layoutsContainer.endLayout.children.length; for (var i=totalChildren2-1; i>=0; --i) { var item2 = layoutsContainer.endLayout.children[0]; item2.parent = layoutsContainer.startLayout; } var totalChildrenL = layoutsContainer.startLayout.children.length; for (var i=totalChildrenL-1; i>=0; --i) { var itemL = layoutsContainer.startLayout.children[0]; itemL.parent = layoutsContainer.mainLayout; } layouter.appletsInParentChange = false; } function upgrader_v010_alignment() { //! IMPORTANT, special case because it needs to be loaded on Component constructor if (!plasmoid.configuration.alignmentUpgraded) { plasmoid.configuration.alignment = plasmoid.configuration.panelPosition; plasmoid.configuration.alignmentUpgraded = true; } } //END functions ////BEGIN interfaces Connections { target: LatteCore.WindowSystem onCompositingActiveChanged: { visibilityManager.updateMaskArea(); } } ////END interfaces /////BEGIN: Title Tooltip/////////// PlasmaCore.Dialog{ id: titleTooltipDialog type: PlasmaCore.Dialog.Tooltip flags: Qt.WindowStaysOnTopHint | Qt.WindowDoesNotAcceptFocus | Qt.ToolTip location: plasmoid.location mainItem: RowLayout{ Layout.fillWidth: true Layout.fillHeight: true PlasmaComponents.Label{ id:titleLbl Layout.leftMargin: 4 Layout.rightMargin: 4 Layout.topMargin: 2 Layout.bottomMargin: 2 text: titleTooltipDialog.title } } visible: false property string title: "" property bool activeItemHovered: false property Item activeItem: null property Item activeItemTooltipParent: null property string activeItemText: "" Component.onCompleted: { parabolic.sglClearZoom.connect(titleTooltipDialog.hide); } Component.onDestruction: { parabolic.sglClearZoom.disconnect(titleTooltipDialog.hide); } function hide(debug){ if (!root.titleTooltips) return; activeItemHovered = false; hideTitleTooltipTimer.start(); } function show(taskItem, text){ if (!root.titleTooltips || (latteApplet && latteApplet.contextMenu)){ return; } activeItemHovered = true; if (activeItem !== taskItem) { activeItem = taskItem; activeItemTooltipParent = taskItem.tooltipVisualParent; activeItemText = text; } if (isReady) { showTitleTooltipTimer.start(); } } function update() { activeItemHovered = true title = activeItemText; visualParent = activeItemTooltipParent; if (latteApplet && latteApplet.windowPreviewIsShown) { latteApplet.hidePreview(); } visible = true; } } Timer { id: showTitleTooltipTimer interval: 100 onTriggered: { if (latteView && latteView.visibility && latteView.visibility.containsMouse) { titleTooltipDialog.update(); } if (titleTooltipDialog.visible) { titleTooltipCheckerToNotShowTimer.start(); } if (root.debugModeTimers) { console.log("containment timer: showTitleTooltipTimer called..."); } } } Timer { id: hideTitleTooltipTimer interval: 200 onTriggered: { if (!titleTooltipDialog.activeItemHovered) { titleTooltipDialog.visible = false; } if (root.debugModeTimers) { console.log("containment timer: hideTitleTooltipTimer called..."); } } } //! Timer to fix #811, rare cases that both a window preview and context menu are //! shown Timer { id: titleTooltipCheckerToNotShowTimer interval: 250 onTriggered: { if (titleTooltipDialog.visible && latteApplet && (latteApplet.contextMenu || latteApplet.windowPreviewIsShown)) { titleTooltipDialog.visible = false; } } } /////END: Title Tooltip/////////// ///////////////BEGIN components Component { id: appletContainerComponent Applet.AppletItem{ animations: _animations indexer: _indexer layouter: _layouter metrics: _metrics parabolic: _parabolic + shortcuts: _shortcuts } } ParabolicManager{ id: _parabolicManager } Indicators.Manager{ id: indicators } Item { id: graphicsSystem readonly property bool isAccelerated: (GraphicsInfo.api !== GraphicsInfo.Software) && (GraphicsInfo.api !== GraphicsInfo.Unknown) } Upgrader { id: upgrader } ///////////////END components PlasmaCore.ColorScope{ id: colorScopePalette } ///////////////BEGIN UI elements //it is used to check if the mouse is outside the layoutsContainer borders, //so in that case the onLeave event behavior should be trigerred RootMouseArea{ id: rootMouseArea } Loader{ active: root.debugModeWindow sourceComponent: Debug.DebugWindow{} } EditMode.Visual{ id:editModeVisual // z: root.behaveAsPlasmaPanel ? 1 : 0 } Item { id: lastSpacer parent: layoutsContainer.mainLayout Layout.fillWidth: true Layout.fillHeight: true z:10 Rectangle{ anchors.fill: parent color: "transparent" border.color: "yellow" border.width: 1 } } Loader{ anchors.fill: parent active: root.debugMode z:10 sourceComponent: Item{ Rectangle{ anchors.fill: parent color: "yellow" opacity: 0.06 } } } VisibilityManager{ id: visibilityManager applets: layoutsContainer.applets } DragDropArea { id: backDropArea anchors.fill: parent readonly property bool higherPriority: latteView && latteView.containsDrag && ((root.dragInfo.isPlasmoid && root.dragInfo.isSeparator) || (foreDropArea.dragInfo.computationsAreValid && !root.dragInfo.isPlasmoid && !root.dragInfo.onlyLaunchers)) Item{ anchors.fill: layoutsContainer Background.MultiLayered{ id: _background } } Layouts.LayoutsContainer { id: layoutsContainer } DragDropArea { id: foreDropArea anchors.fill: parent visible: !backDropArea.higherPriority isForeground: true /* Rectangle { anchors.fill: parent color: "blue" opacity: 0.5 }*/ } } Colorizer.Manager { id: colorizerManager } Item { id: dndSpacer width: root.isHorizontal ? length : thickness height: root.isHorizontal ? thickness : length readonly property bool isDndSpacer: true readonly property int length: metrics.totals.length readonly property int thickness: metrics.totals.thickness + metrics.margin.screenEdge Layout.preferredWidth: width Layout.preferredHeight: height opacity: 0 z:1500 LatteComponents.AddItem{ id: dndSpacerAddItem width: root.isHorizontal ? parent.width : parent.width - metrics.margin.screenEdge height: root.isHorizontal ? parent.height - metrics.margin.screenEdge: parent.height states:[ State{ name: "bottom" when: plasmoid.location === PlasmaCore.Types.BottomEdge AnchorChanges{ target: dndSpacerAddItem; anchors.horizontalCenter: parent.horizontalCenter; anchors.verticalCenter: undefined; anchors.right: undefined; anchors.left: undefined; anchors.top: undefined; anchors.bottom: parent.bottom; } PropertyChanges{ target: dndSpacerAddItem; anchors.leftMargin: 0; anchors.rightMargin: 0; anchors.topMargin:0; anchors.bottomMargin: metrics.margin.screenEdge; anchors.horizontalCenterOffset: 0; anchors.verticalCenterOffset: 0; } }, State{ name: "top" when: plasmoid.location === PlasmaCore.Types.TopEdge AnchorChanges{ target: dndSpacerAddItem; anchors.horizontalCenter: parent.horizontalCenter; anchors.verticalCenter: undefined; anchors.right: undefined; anchors.left: undefined; anchors.top: parent.top; anchors.bottom: undefined; } PropertyChanges{ target: dndSpacerAddItem; anchors.leftMargin: 0; anchors.rightMargin: 0; anchors.topMargin: metrics.margin.screenEdge; anchors.bottomMargin: 0; anchors.horizontalCenterOffset: 0; anchors.verticalCenterOffset: 0; } }, State{ name: "left" when: plasmoid.location === PlasmaCore.Types.LeftEdge AnchorChanges{ target: dndSpacerAddItem; anchors.horizontalCenter: undefined; anchors.verticalCenter: parent.verticalCenter; anchors.right: undefined; anchors.left: parent.left; anchors.top: undefined; anchors.bottom: undefined; } PropertyChanges{ target: dndSpacerAddItem; anchors.leftMargin: metrics.margin.screenEdge; anchors.rightMargin: 0; anchors.topMargin:0; anchors.bottomMargin: 0; anchors.horizontalCenterOffset: 0; anchors.verticalCenterOffset: 0; } }, State{ name: "right" when: plasmoid.location === PlasmaCore.Types.RightEdge AnchorChanges{ target: dndSpacerAddItem; anchors.horizontalCenter: undefined; anchors.verticalCenter: parent.verticalCenter; anchors.right: parent.right; anchors.left: undefined; anchors.top: undefined; anchors.bottom: undefined; } PropertyChanges{ target: dndSpacerAddItem; anchors.leftMargin: 0; anchors.rightMargin: metrics.margin.screenEdge; anchors.topMargin:0; anchors.bottomMargin: 0; anchors.horizontalCenterOffset: 0; anchors.verticalCenterOffset: 0; } } ] } } ///////////////END UI elements ///////////////BEGIN ABILITIES Ability.Animations { id: _animations metrics: _metrics settings: universalSettings } Ability.AutoSize { id: _autosize layouts: layoutsContainer layouter: _layouter metrics: _metrics visibility: visibilityManager } Ability.Indexer { id: _indexer layouts: layoutsContainer } Ability.Layouter { id: _layouter animations: _animations indexer: _indexer layouts: layoutsContainer } Ability.Metrics { id: _metrics animations: _animations autosize: _autosize background: _background indicators: indicatorsManager } Ability.ParabolicEffect { id: _parabolic animations: _animations applets: layoutsContainer.applets view: latteView } + Ability.PositionShortcuts { + id: _shortcuts + layouts: layoutsContainer + } + LatteApp.Interfaces { id: _interfaces plasmoidInterface: plasmoid Component.onCompleted: { view.interfacesGraphicObj = _interfaces; } onViewChanged: { if (view) { view.interfacesGraphicObj = _interfaces; } } } ///////////////END ABILITIES ///////////////BEGIN TIMER elements //! It is used in order to slide-in the latteView on startup Timer{ id: inStartupTimer interval: 1500 repeat: false onTriggered: { if (inStartup) { visibilityManager.slotMustBeShown(); } } } ///////////////END TIMER elements Loader{ anchors.fill: parent active: root.debugModeLocalGeometry sourceComponent: Rectangle{ x: latteView.localGeometry.x y: latteView.localGeometry.y width: latteView.localGeometry.width height: latteView.localGeometry.height color: "blue" border.width: 2 border.color: "red" opacity: 0.35 } } } diff --git a/containment/package/contents/ui/abilities/PositionShortcuts.qml b/declarativeimports/abilities/bridge/PositionShortcuts.qml similarity index 75% copy from containment/package/contents/ui/abilities/PositionShortcuts.qml copy to declarativeimports/abilities/bridge/PositionShortcuts.qml index d6cb6509..144899a8 100644 --- a/containment/package/contents/ui/abilities/PositionShortcuts.qml +++ b/declarativeimports/abilities/bridge/PositionShortcuts.qml @@ -1,29 +1,28 @@ /* -* Copyright 2019 Michail Vourlakos +* Copyright 2020 Michail Vourlakos * * 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 . */ -import QtQuick 2.8 +import QtQuick 2.0 -import org.kde.plasma.core 2.0 as PlasmaCore -import org.kde.plasma.plasmoid 2.0 - -import "./privates" as Ability - -Ability.PositionShortcutsPrivate { +Item { + id: shortcutsBridge + property int appletIndex: -1 + property Item host: null + property Item client: null } diff --git a/declarativeimports/abilities/bridge/qmldir b/declarativeimports/abilities/bridge/qmldir index 5ba776a7..7fc30c3f 100644 --- a/declarativeimports/abilities/bridge/qmldir +++ b/declarativeimports/abilities/bridge/qmldir @@ -1,4 +1,5 @@ module org.kde.latte.abilities.applets Indexer 0.1 Indexer.qml ParabolicEffect 0.1 ParabolicEffect.qml +PositionShortcuts 0.1 PositionShortcuts.qml