1/*
2    SPDX-FileCopyrightText: 2016 Smith AR <audoban@openmailbox.org>
3    SPDX-FileCopyrightText: 2016 Michail Vourlakos <mvourlakos@gmail.com>
4    SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7import QtQuick 2.8
8import QtQuick.Layouts 1.1
9import QtQuick.Window 2.2
10import QtGraphicalEffects 1.0
11
12import org.kde.plasma.core 2.0 as PlasmaCore
13import org.kde.plasma.components 2.0 as PlasmaComponents
14import org.kde.kquickcontrolsaddons 2.0
15import org.kde.plasma.plasmoid 2.0
16
17import org.kde.latte.abilities.host 0.1 as AbilityHost
18
19import org.kde.latte.core 0.2 as LatteCore
20import org.kde.latte.components 1.0 as LatteComponents
21import org.kde.latte.private.app 0.1 as LatteApp
22import org.kde.latte.private.containment 0.1 as LatteContainment
23
24import "abilities" as Ability
25import "applet" as Applet
26import "colorizer" as Colorizer
27import "editmode" as EditMode
28import "layouts" as Layouts
29import "./background" as Background
30import "./debugger" as Debugger
31
32Item {
33    id: root
34    objectName: "containmentViewLayout"
35
36    LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft && !root.isVertical
37    LayoutMirroring.childrenInherit: true
38
39    //// BEGIN SIGNALS
40    signal destroyInternalViewSplitters();
41    signal emptyAreasWheel(QtObject wheel);
42    signal separatorsUpdated();
43    signal updateEffectsArea();
44    signal updateIndexes();
45
46    signal broadcastedToApplet(string pluginName, string action, variant value);
47    //// END SIGNALS
48
49    ////BEGIN properties
50    readonly property int version: LatteCore.Environment.makeVersion(0,9,75)
51    readonly property bool kirigamiLibraryIsFound: LatteCore.Environment.frameworksVersion >= LatteCore.Environment.makeVersion(5,69,0)
52
53    property bool backgroundOnlyOnMaximized: plasmoid.configuration.backgroundOnlyOnMaximized
54    readonly property bool behaveAsPlasmaPanel: viewType === LatteCore.Types.PanelView
55    readonly property bool behaveAsDockWithMask: !behaveAsPlasmaPanel
56
57    readonly property bool viewIsAvailable: latteView && latteView.visibility && latteView.effects
58
59    property int viewType: {
60        if (!latteView || !latteView.visibility) {
61            return LatteCore.Types.DockView;
62        }
63
64        if (screenEdgeMarginEnabled && root.floatingInternalGapIsForced) {
65            //! dont use when floating views are requesting internal floating gap which is in client side
66            return LatteCore.Types.DockView;
67        }
68
69        return viewTypeInQuestion;
70    }
71
72    property int viewTypeInQuestion: {
73        //! viewType as chosen before considering other optios such as floating internal gap enforcement.
74        //! It helps with binding loops
75        if (!latteView || !latteView.visibility) {
76            return LatteCore.Types.DockView;
77        }
78
79        if (background.customShadowedRectangleIsEnabled) {
80            return LatteCore.Types.DockView;
81        }
82
83        var staticLayout = (plasmoid.configuration.minLength === plasmoid.configuration.maxLength);
84
85        if ((plasmoid.configuration.alignment === LatteCore.Types.Justify || staticLayout)
86                && background.isGreaterThanItemThickness
87                && (parabolic.factor.maxZoom === 1.0)) {
88            return LatteCore.Types.PanelView;
89        }
90
91        return LatteCore.Types.DockView;
92    }
93
94    property bool blurEnabled: plasmoid.configuration.blurEnabled && (!forceTransparentPanel || forcePanelForBusyBackground)
95
96    readonly property bool inDraggingOverAppletOrOutOfContainment: latteView && latteView.containsDrag && !backDropArea.containsDrag
97
98    readonly property Item dragInfo: Item {
99        property bool entered: backDropArea.dragInfo.entered
100        property bool isTask: backDropArea.dragInfo.isTask
101        property bool isPlasmoid: backDropArea.dragInfo.isPlasmoid
102        property bool isSeparator: backDropArea.dragInfo.isSeparator
103        property bool isLatteTasks: backDropArea.dragInfo.isLatteTasks
104        property bool onlyLaunchers: backDropArea.dragInfo.onlyLaunchers
105    }
106
107    property bool containsOnlyPlasmaTasks: latteView ? latteView.extendedInterface.hasPlasmaTasks && !latteView.extendedInterface.hasLatteTasks : false
108    property bool dockContainsMouse: latteView && latteView.visibility ? latteView.visibility.containsMouse : false
109
110    property bool disablePanelShadowMaximized: plasmoid.configuration.disablePanelShadowForMaximized && LatteCore.WindowSystem.compositingActive
111    property bool drawShadowsExternal: panelShadowsActive && behaveAsPlasmaPanel
112
113    property bool editMode: plasmoid.userConfiguring
114    property bool windowIsTouching: latteView && latteView.windowsTracker
115                                    && (latteView.windowsTracker.currentScreen.activeWindowTouching
116                                        || latteView.windowsTracker.currentScreen.activeWindowTouchingEdge
117                                        || hasExpandedApplet)
118
119    property bool floatingInternalGapIsForced: plasmoid.configuration.floatingInternalGapIsForced
120
121    property bool hasFloatingGapInputEventsDisabled: root.screenEdgeMarginEnabled
122                                                     && !latteView.byPassWM
123                                                     && !root.inConfigureAppletsMode
124                                                     && !parabolic.isEnabled
125                                                     && (root.behaveAsPlasmaPanel || (root.behaveAsDockWithMask && !root.floatingInternalGapIsForced))
126
127    property bool forceSolidPanel: (latteView && latteView.visibility
128                                    && LatteCore.WindowSystem.compositingActive
129                                    && !inConfigureAppletsMode
130                                    && userShowPanelBackground
131                                    && ( (plasmoid.configuration.solidBackgroundForMaximized
132                                          && !(hasExpandedApplet && !plasmaBackgroundForPopups)
133                                          && (latteView.windowsTracker.currentScreen.existsWindowTouching
134                                              || latteView.windowsTracker.currentScreen.existsWindowTouchingEdge))
135                                        || (hasExpandedApplet && plasmaBackgroundForPopups) ))
136                                   || !LatteCore.WindowSystem.compositingActive
137
138    property bool forceTransparentPanel: root.backgroundOnlyOnMaximized
139                                         && latteView && latteView.visibility
140                                         && LatteCore.WindowSystem.compositingActive
141                                         && !inConfigureAppletsMode
142                                         && !forceSolidPanel
143                                         && !(latteView.windowsTracker.currentScreen.existsWindowTouching
144                                              || latteView.windowsTracker.currentScreen.existsWindowTouchingEdge)
145                                         && !(windowColors === LatteContainment.Types.ActiveWindowColors && selectedWindowsTracker.existsWindowActive)
146
147    property bool forcePanelForBusyBackground: userShowPanelBackground && (normalBusyForTouchingBusyVerticalView
148                                                                           || ( root.forceTransparentPanel
149                                                                               && colorizerManager.backgroundIsBusy
150                                                                               && root.themeColors === LatteContainment.Types.SmartThemeColors))
151
152    property bool normalBusyForTouchingBusyVerticalView: (latteView && latteView.windowsTracker /*is touching a vertical view that is in busy state and the user prefers isBusy transparency*/
153                                                          && latteView.windowsTracker.currentScreen.isTouchingBusyVerticalView
154                                                          && plasmoid.configuration.backgroundOnlyOnMaximized)
155
156    property bool appletIsDragged: root.dragOverlay && root.dragOverlay.pressed
157    property bool hideThickScreenGap: false /*set through binding*/
158    property bool hideLengthScreenGaps: false /*set through binding*/
159
160    property bool mirrorScreenGap: screenEdgeMarginEnabled
161                                   && plasmoid.configuration.floatingGapIsMirrored
162                                   && latteView.visibility.mode === LatteCore.Types.AlwaysVisible
163
164
165
166    property int themeColors: plasmoid.configuration.themeColors
167    property int windowColors: plasmoid.configuration.windowColors
168
169    property bool colorizerEnabled: themeColors !== LatteContainment.Types.PlasmaThemeColors || windowColors !== LatteContainment.Types.NoneWindowColors
170
171    property bool plasmaBackgroundForPopups: plasmoid.configuration.plasmaBackgroundForPopups
172
173    readonly property bool hasExpandedApplet: latteView && latteView.extendedInterface.hasExpandedApplet;
174    readonly property bool hasUserSpecifiedBackground: (latteView && latteView.layout && latteView.layout.background.startsWith("/")) ?
175                                                           true : false
176
177    readonly property bool inConfigureAppletsMode: root.editMode && plasmoid.configuration.inConfigureAppletsMode
178
179    property bool closeActiveWindowEnabled: plasmoid.configuration.closeActiveWindowEnabled
180    property bool dragActiveWindowEnabled: plasmoid.configuration.dragActiveWindowEnabled
181    property bool immutable: plasmoid.immutable
182    property bool inFullJustify: (plasmoid.configuration.alignment === LatteCore.Types.Justify) && (maxLengthPerCentage===100)
183    property bool inStartup: true
184
185    property bool isHorizontal: plasmoid.formFactor === PlasmaCore.Types.Horizontal
186    property bool isVertical: !isHorizontal
187
188    property bool mouseWheelActions: plasmoid.configuration.mouseWheelActions
189    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
190
191    //FIXME: possibly this is going to be the default behavior, this user choice
192    //has been dropped from the Dock Configuration Window
193    //property bool smallAutomaticIconJumps: plasmoid.configuration.smallAutomaticIconJumps
194    property bool smallAutomaticIconJumps: true
195
196    property bool userShowPanelBackground: LatteCore.WindowSystem.compositingActive ? plasmoid.configuration.useThemePanel : true
197    property bool useThemePanel: noApplets === 0 || !LatteCore.WindowSystem.compositingActive ?
198                                     true : (plasmoid.configuration.useThemePanel || plasmoid.configuration.solidBackgroundForMaximized)
199
200    property bool plasma515: LatteCore.Environment.plasmaDesktopVersion >= LatteCore.Environment.makeVersion(5,15,0)
201    property bool plasma518: LatteCore.Environment.plasmaDesktopVersion >= LatteCore.Environment.makeVersion(5,18,0)
202
203    readonly property int minAppletLengthInConfigure: 16
204    readonly property int maxJustifySplitterSize: 64
205
206    property real minLengthPerCentage: plasmoid.configuration.minLength
207    property real maxLengthPerCentage: hideLengthScreenGaps ? 100 : plasmoid.configuration.maxLength
208
209    property int minLength: {
210        if (myView.alignment === LatteCore.Types.Justify) {
211            return maxLength;
212        }
213
214        if (root.isHorizontal) {
215            return behaveAsPlasmaPanel && LatteCore.WindowSystem.compositingActive ? width : width * (minLengthPerCentage/100)
216        } else {
217            return behaveAsPlasmaPanel && LatteCore.WindowSystem.compositingActive ? height : height * (minLengthPerCentage/100)
218        }
219    }
220
221    property int maxLength: {
222        if (root.isHorizontal) {
223            return behaveAsPlasmaPanel ? width : width * (maxLengthPerCentage/100)
224        } else {
225            return behaveAsPlasmaPanel ? height : height * (maxLengthPerCentage/100)
226        }
227    }
228
229    property int scrollAction: plasmoid.configuration.scrollAction
230
231    property bool panelOutline: plasmoid.configuration.panelOutline
232    property int panelEdgeSpacing: Math.max(background.lengthMargins, 1.5*myView.itemShadow.size)
233
234    property bool backgroundShadowsInRegularStateEnabled: LatteCore.WindowSystem.compositingActive
235                                                          && userShowPanelBackground
236                                                          && plasmoid.configuration.panelShadows
237
238    property bool panelShadowsActive: {
239        if (!userShowPanelBackground) {
240            return false;
241        }
242
243        if (inConfigureAppletsMode) {
244            return plasmoid.configuration.panelShadows;
245        }
246
247        var forcedNoShadows = (plasmoid.configuration.panelShadows && disablePanelShadowMaximized
248                               && latteView && latteView.windowsTracker && latteView.windowsTracker.currentScreen.activeWindowMaximized);
249
250        if (forcedNoShadows) {
251            return false;
252        }
253
254        var transparencyCheck = (blurEnabled || (!blurEnabled && background.currentOpacity>20));
255
256        //! Draw shadows for isBusy state only when current background opacity is greater than 10%
257        if (plasmoid.configuration.panelShadows && root.forcePanelForBusyBackground && transparencyCheck) {
258            return true;
259        }
260
261        if (( (plasmoid.configuration.panelShadows && !root.backgroundOnlyOnMaximized)
262             || (plasmoid.configuration.panelShadows && root.backgroundOnlyOnMaximized && !root.forceTransparentPanel))
263                && !forcedNoShadows) {
264            return true;
265        }
266
267        if (hasExpandedApplet && plasmaBackgroundForPopups) {
268            return true;
269        }
270
271        return false;
272    }
273
274    property int offset: {
275        if (behaveAsPlasmaPanel) {
276            return 0;
277        }
278
279        if (root.isHorizontal) {
280            return width * (plasmoid.configuration.offset/100);
281        } else {
282            height * (plasmoid.configuration.offset/100)
283        }
284    }
285
286    property int editShadow: {
287        if (!LatteCore.WindowSystem.compositingActive) {
288            return 0;
289        } else if (latteView && latteView.screenGeometry) {
290            return latteView.screenGeometry.height/90;
291        } else {
292            return 7;
293        }
294    }
295
296    property bool screenEdgeMarginEnabled: plasmoid.configuration.screenEdgeMargin >= 0
297
298    property int widthMargins: root.isVertical ? metrics.totals.thicknessEdges : metrics.totals.lengthEdges
299    property int heightMargins: root.isHorizontal ? metrics.totals.thicknessEdges : metrics.totals.lengthEdges
300
301    property var iconsArray: [16, 22, 32, 48, 64, 96, 128, 256]
302
303    property Item dragOverlay: _dragOverlay
304    property Item toolBox
305
306    readonly property alias animations: _animations
307    readonly property alias autosize: _autosize
308    readonly property alias background: _background
309    readonly property alias debug: _debug
310    readonly property alias environment: _environment
311    readonly property alias indexer: _indexer
312    readonly property alias indicators: _indicators
313    readonly property alias layouter: _layouter
314    readonly property alias launchers: _launchers
315    readonly property alias metrics: _metrics
316    readonly property alias myView: _myView
317    readonly property alias parabolic: _parabolic
318    readonly property alias thinTooltip: _thinTooltip
319    readonly property alias userRequests: _userRequests
320
321    readonly property alias maskManager: visibilityManager
322    readonly property alias layoutsContainerItem: layoutsContainer
323
324    readonly property alias latteView: _interfaces.view
325    readonly property alias layoutsManager: _interfaces.layoutsManager
326    readonly property alias shortcutsEngine: _interfaces.globalShortcuts
327    readonly property alias themeExtended: _interfaces.themeExtended
328    readonly property alias universalSettings: _interfaces.universalSettings
329
330    readonly property QtObject selectedWindowsTracker: {
331        if (latteView && latteView.windowsTracker) {
332            switch(plasmoid.configuration.activeWindowFilter) {
333            case LatteContainment.Types.ActiveInCurrentScreen:
334                return latteView.windowsTracker.currentScreen;
335            case LatteContainment.Types.ActiveFromAllScreens:
336                return latteView.windowsTracker.allScreens;
337            }
338        }
339
340        return null;
341    }
342
343    Plasmoid.backgroundHints: PlasmaCore.Types.NoBackground
344
345    //// BEGIN properties in functions
346    property int noApplets: {
347        var count1 = 0;
348        var count2 = 0;
349
350        count1 = layoutsContainer.mainLayout.children.length;
351        var tempLength = layoutsContainer.mainLayout.children.length;
352
353        for (var i=tempLength-1; i>=0; --i) {
354            var applet = layoutsContainer.mainLayout.children[i];
355            if (applet && (applet === dndSpacer ||  applet.isInternalViewSplitter))
356                count1--;
357        }
358
359        count2 = layoutsContainer.endLayout.children.length;
360        tempLength = layoutsContainer.endLayout.children.length;
361
362        for (var i=tempLength-1; i>=0; --i) {
363            var applet = layoutsContainer.endLayout.children[i];
364            if (applet && (applet === dndSpacer || applet.isInternalViewSplitter))
365                count2--;
366        }
367
368        return (count1 + count2);
369    }
370
371    ///The index of user's current icon size
372    property int currentIconIndex:{
373        for(var i=iconsArray.length-1; i>=0; --i){
374            if(iconsArray[i] === metrics.iconSize){
375                return i;
376            }
377        }
378        return 3;
379    }
380
381    //// END properties in functions
382
383    ////////////////END properties
384
385    //////////////START OF BINDINGS
386
387    //! Wait until the mouse leaves the view
388    Binding {
389        target: root
390        property: "hideThickScreenGap"
391        when: !(plasmoid.configuration.floatingGapHidingWaitsMouse && dockContainsMouse)
392        value: screenEdgeMarginEnabled
393               && plasmoid.configuration.hideFloatingGapForMaximized
394               && latteView && latteView.windowsTracker
395               && latteView.windowsTracker.currentScreen.existsWindowMaximized
396    }
397
398    //! Binding is needed in order for hideLengthScreenGaps to be activated or not only after
399    //! View sliding in/out has finished. This way the animation is smoother for behaveAsPlasmaPanels
400    Binding{
401        target: root
402        property: "hideLengthScreenGaps"
403        when: latteView && latteView.positioner && latteView.visibility
404              && ((root.behaveAsPlasmaPanel && latteView.positioner.slideOffset === 0)
405                  || root.behaveAsDockWithMask)
406              && !(plasmoid.configuration.floatingGapHidingWaitsMouse && dockContainsMouse)
407        value: (hideThickScreenGap
408                && (latteView.visibility.mode === LatteCore.Types.AlwaysVisible
409                    || latteView.visibility.mode === LatteCore.Types.WindowsGoBelow)
410                && (plasmoid.configuration.alignment === LatteCore.Types.Justify)
411                && plasmoid.configuration.maxLength>85)
412    }
413
414    //////////////END OF BINDINGS
415
416
417    //////////////START OF CONNECTIONS
418    onEditModeChanged: {
419        if (!editMode) {
420            layouter.updateSizeForAppletsInFill();
421        }
422
423        //! This is used in case the dndspacer has been left behind
424        //! e.g. the user drops a folder and a context menu is appearing
425        //! but the user decides to not make a choice for the applet type
426        if (dndSpacer.parent !== root) {
427            dndSpacer.parent = root;
428        }
429
430        //Block Hiding events
431        if (editMode) {
432            latteView.visibility.addBlockHidingEvent("main[qml]::inEditMode()");
433        } else {
434            latteView.visibility.removeBlockHidingEvent("main[qml]::inEditMode()");
435        }
436    }
437
438    onInConfigureAppletsModeChanged: {
439        updateIndexes();
440    }
441
442    //! It is used only when the user chooses different alignment types and not during startup
443    Connections {
444        target: latteView ? latteView : null
445        onAlignmentChanged: {
446            if (latteView.alignment === LatteCore.Types.NoneAlignment) {
447                return;
448            }
449
450            var previousalignment = plasmoid.configuration.alignment;
451
452            if (latteView.alignment===LatteCore.Types.Justify && previousalignment!==LatteCore.Types.Justify) { // main -> justify
453                layouter.appletsInParentChange = true;
454                fastLayoutManager.addJustifySplittersInMainLayout();
455                console.log("LAYOUTS: Moving applets from MAIN to THREE Layouts mode...");
456                fastLayoutManager.moveAppletsBasedOnJustifyAlignment();
457                layouter.appletsInParentChange = false;
458            } else if (latteView.alignment!==LatteCore.Types.Justify && previousalignment===LatteCore.Types.Justify ) { // justify ->main
459                layouter.appletsInParentChange = true;
460                console.log("LAYOUTS: Moving applets from THREE to MAIN Layout mode...");
461                fastLayoutManager.joinLayoutsToMainLayout();
462                layouter.appletsInParentChange = false;
463            }
464
465            plasmoid.configuration.alignment = latteView.alignment;
466            fastLayoutManager.save();
467        }
468    }
469
470    onLatteViewChanged: {
471        if (latteView) {
472            if (latteView.positioner) {
473                latteView.positioner.hidingForRelocationStarted.connect(visibilityManager.slotHideDockDuringLocationChange);
474                latteView.positioner.showingAfterRelocationFinished.connect(visibilityManager.slotShowDockAfterLocationChange);
475            }
476
477            if (latteView.visibility) {
478                latteView.visibility.onContainsMouseChanged.connect(visibilityManager.slotContainsMouseChanged);
479                latteView.visibility.onMustBeHide.connect(visibilityManager.slotMustBeHide);
480                latteView.visibility.onMustBeShown.connect(visibilityManager.slotMustBeShown);
481            }
482        }
483    }
484
485    Connections {
486        target: latteView
487        onPositionerChanged: {
488            if (latteView.positioner) {
489                latteView.positioner.hidingForRelocationStarted.connect(visibilityManager.slotHideDockDuringLocationChange);
490                latteView.positioner.showingAfterRelocationFinished.connect(visibilityManager.slotShowDockAfterLocationChange);
491            }
492        }
493
494        onVisibilityChanged: {
495            if (latteView.visibility) {
496                latteView.visibility.onContainsMouseChanged.connect(visibilityManager.slotContainsMouseChanged);
497                latteView.visibility.onMustBeHide.connect(visibilityManager.slotMustBeHide);
498                latteView.visibility.onMustBeShown.connect(visibilityManager.slotMustBeShown);
499            }
500        }
501    }
502
503
504    onMaxLengthChanged: {
505        layouter.updateSizeForAppletsInFill();
506    }
507
508    onToolBoxChanged: {
509        if (toolBox) {
510            toolBox.visible = false;
511        }
512    }
513
514    onIsVerticalChanged: {
515        if (isVertical) {
516            if (plasmoid.configuration.alignment === LatteCore.Types.Left)
517                plasmoid.configuration.alignment = LatteCore.Types.Top;
518            else if (plasmoid.configuration.alignment === LatteCore.Types.Right)
519                plasmoid.configuration.alignment = LatteCore.Types.Bottom;
520        } else {
521            if (plasmoid.configuration.alignment === LatteCore.Types.Top)
522                plasmoid.configuration.alignment = LatteCore.Types.Left;
523            else if (plasmoid.configuration.alignment === LatteCore.Types.Bottom)
524                plasmoid.configuration.alignment = LatteCore.Types.Right;
525        }
526    }
527
528    Component.onCompleted: {
529        upgrader_v010_alignment();
530
531        fastLayoutManager.restore();
532        plasmoid.action("configure").visible = !plasmoid.immutable;
533        plasmoid.action("configure").enabled = !plasmoid.immutable;
534    }
535
536    Component.onDestruction: {
537        console.debug("Destroying Latte Dock Containment ui...");
538
539        layouter.appletsInParentChange = true;
540        fastLayoutManager.save();
541
542        if (latteView) {
543            if (latteView.positioner) {
544                latteView.positioner.hidingForRelocationStarted.disconnect(visibilityManager.slotHideDockDuringLocationChange);
545                latteView.positioner.showingAfterRelocationFinished.disconnect(visibilityManager.slotShowDockAfterLocationChange);
546            }
547
548            if (latteView.visibility) {
549                latteView.visibility.onContainsMouseChanged.disconnect(visibilityManager.slotContainsMouseChanged);
550                latteView.visibility.onMustBeHide.disconnect(visibilityManager.slotMustBeHide);
551                latteView.visibility.onMustBeShown.disconnect(visibilityManager.slotMustBeShown);
552            }
553        }
554    }
555
556    Containment.onAppletAdded: fastLayoutManager.addAppletItem(applet, x, y);
557    Containment.onAppletRemoved: fastLayoutManager.removeAppletItem(applet);
558
559    Plasmoid.onUserConfiguringChanged: {
560        if (plasmoid.userConfiguring) {
561            for (var i = 0; i < plasmoid.applets.length; ++i) {
562                plasmoid.applets[i].expanded = false;
563            }
564        }
565    }
566
567    Plasmoid.onImmutableChanged: {
568        plasmoid.action("configure").visible = !plasmoid.immutable;
569        plasmoid.action("configure").enabled = !plasmoid.immutable;
570    }
571    //////////////END OF CONNECTIONS
572
573    //////////////START OF FUNCTIONS
574    function createAppletItem(applet) {
575        var appletItem = appletItemComponent.createObject(dndSpacer.parent);
576        appletItem.applet = applet;
577        applet.parent = appletItem.appletWrapper;
578        applet.anchors.fill = appletItem.appletWrapper;
579        applet.visible = true;
580
581        // don't show applet if it chooses to be hidden but still make it  accessible in the panelcontroller
582        appletItem.visible = Qt.binding(function() {
583            return applet.status !== PlasmaCore.Types.HiddenStatus || (!plasmoid.immutable && root.inConfigureAppletsMode)
584        });
585
586        return appletItem;
587    }
588
589    function createJustifySplitter() {
590        var splitter = appletItemComponent.createObject(root);
591        splitter.internalSplitterId = internalViewSplittersCount()+1;
592        splitter.visible = true;
593        return splitter;
594    }
595
596    //! it is used in order to check the right click position
597    //! the only way to take into account the visual appearance
598    //! of the applet (including its spacers)
599    function appletContainsPos(appletId, pos){
600        for (var i = 0; i < layoutsContainer.startLayout.children.length; ++i) {
601            var child = layoutsContainer.startLayout.children[i];
602
603            if (child && child.applet && child.applet.id === appletId && child.containsPos(pos))
604                return true;
605        }
606
607        for (var i = 0; i < layoutsContainer.mainLayout.children.length; ++i) {
608            var child = layoutsContainer.mainLayout.children[i];
609
610            if (child && child.applet && child.applet.id === appletId && child.containsPos(pos))
611                return true;
612        }
613
614        for (var i = 0; i < layoutsContainer.endLayout.children.length; ++i) {
615            var child = layoutsContainer.endLayout.children[i];
616
617            if (child && child.applet && child.applet.id === appletId && child.containsPos(pos))
618                return true;
619        }
620
621        return false;
622    }
623
624    function internalViewSplittersCount(){
625        var splitters = 0;
626        for (var container in layoutsContainer.startLayout.children) {
627            var item = layoutsContainer.startLayout.children[container];
628            if(item && item.isInternalViewSplitter) {
629                splitters = splitters + 1;
630            }
631        }
632
633        for (var container in layoutsContainer.mainLayout.children) {
634            var item = layoutsContainer.mainLayout.children[container];
635            if(item && item.isInternalViewSplitter) {
636                splitters = splitters + 1;
637            }
638        }
639
640        for (var container in layoutsContainer.endLayout.children) {
641            var item = layoutsContainer.endLayout.children[container];
642            if(item && item.isInternalViewSplitter) {
643                splitters = splitters + 1;
644            }
645        }
646
647        return splitters;
648    }
649
650    function mouseInCanBeHoveredApplet(){
651        var applets = layoutsContainer.startLayout.children;
652
653        for(var i=0; i<applets.length; ++i){
654            var applet = applets[i];
655
656            if(applet && applet.containsMouse && !applet.originalAppletBehavior && applet.parabolicEffectIsSupported){
657                return true;
658            }
659        }
660
661        applets = layoutsContainer.mainLayout.children;
662
663        for(var i=0; i<applets.length; ++i){
664            var applet = applets[i];
665
666            if(applet && applet.containsMouse && !applet.originalAppletBehavior && applet.parabolicEffectIsSupported){
667                return true;
668            }
669        }
670
671        ///check second layout also
672        applets = layoutsContainer.endLayout.children;
673
674        for(var i=0; i<applets.length; ++i){
675            var applet = applets[i];
676
677            if(applet && applet.containsMouse && !applet.originalAppletBehavior && applet.parabolicEffectIsSupported){
678                return true;
679            }
680        }
681
682        return false;
683    }
684
685    function sizeIsFromAutomaticMode(size){
686
687        for(var i=iconsArray.length-1; i>=0; --i){
688            if(iconsArray[i] === size){
689                return true;
690            }
691        }
692
693        return false;
694    }
695
696    function upgrader_v010_alignment() {
697        //! IMPORTANT, special case because it needs to be loaded on Component constructor
698        if (!plasmoid.configuration.alignmentUpgraded) {
699            plasmoid.configuration.alignment = plasmoid.configuration.panelPosition;
700            plasmoid.configuration.alignmentUpgraded = true;
701        }
702    }
703    //END functions
704
705    ///////////////BEGIN components
706    Component {
707        id: appletItemComponent
708        Applet.AppletItem{
709            animations: _animations
710            debug: _debug
711            environment: _environment
712            indexer: _indexer
713            indicators: _indicators
714            launchers: _launchers
715            layouter: _layouter
716            layouts: layoutsContainer
717            metrics: _metrics
718            myView: _myView
719            parabolic: _parabolic
720            shortcuts: _shortcuts
721            thinTooltip: _thinTooltip
722            userRequests: _userRequests
723        }
724    }
725
726    Upgrader {
727        id: upgrader
728    }
729
730    ///////////////END components
731
732    PlasmaCore.ColorScope{
733        id: colorScopePalette
734    }
735
736    LatteContainment.LayoutManager{
737        id:fastLayoutManager
738        plasmoidObj: plasmoid
739        rootItem: root
740        dndSpacerItem: dndSpacer
741        mainLayout: layoutsContainer.mainLayout
742        startLayout: layoutsContainer.startLayout
743        endLayout: layoutsContainer.endLayout
744        metrics: _metrics
745
746        onLockedZoomAppletsChanged: plasmoid.configuration.lockedZoomApplets = fastLayoutManager.lockedZoomApplets;
747        onUserBlocksColorizingAppletsChanged: plasmoid.configuration.userBlocksColorizingApplets = fastLayoutManager.userBlocksColorizingApplets;
748
749        onAppletOrderChanged: {
750            plasmoid.configuration.appletOrder = fastLayoutManager.appletOrder;
751            root.updateIndexes();
752        }
753
754        onSplitterPositionChanged: {
755            plasmoid.configuration.splitterPosition = fastLayoutManager.splitterPosition;
756            root.updateIndexes();
757        }
758
759        onSplitterPosition2Changed: {
760            plasmoid.configuration.splitterPosition2 = fastLayoutManager.splitterPosition2;
761            root.updateIndexes();
762        }
763    }
764
765    ///////////////BEGIN UI elements
766
767    Loader{
768        active: debug.windowEnabled
769        sourceComponent: Debugger.DebugWindow{}
770    }
771
772    Loader{
773        anchors.fill: parent
774        active: debug.graphicsEnabled
775        z:10
776
777        sourceComponent: Item{
778            Rectangle{
779                anchors.fill: parent
780                color: "yellow"
781                opacity: 0.06
782            }
783        }
784    }
785
786    BindingsExternal {
787        id: bindingsExternal
788    }
789
790    VisibilityManager{
791        id: visibilityManager
792        layouts: layoutsContainer
793    }
794
795    DragDropArea {
796        id: backDropArea
797        anchors.fill: parent
798
799        Item{
800            anchors.fill: layoutsContainer
801
802            Background.MultiLayered{
803                id: _background
804            }
805        }
806
807        Layouts.LayoutsContainer {
808            id: layoutsContainer
809        }
810    }
811
812    Colorizer.Manager {
813        id: colorizerManager
814    }
815
816    EditMode.ConfigOverlay{
817        id: _dragOverlay
818    }
819
820    Item {
821        id: dndSpacer
822
823        width: root.isHorizontal ? length : thickness
824        height: root.isHorizontal ? thickness : length
825
826        property int length: opacity > 0 ? (dndSpacerAddItem.length + metrics.totals.lengthEdges + metrics.totals.lengthPaddings) : 0
827
828        readonly property bool isDndSpacer: true
829        readonly property int thickness: metrics.totals.thickness + metrics.margin.screenEdge
830        readonly property int maxLength: 96
831
832        Layout.minimumWidth: width
833        Layout.minimumHeight: height
834        Layout.preferredWidth: Layout.minimumWidth
835        Layout.preferredHeight: Layout.minimumHeight
836        Layout.maximumWidth: Layout.minimumWidth
837        Layout.maximumHeight: Layout.minimumHeight
838        opacity: 0
839        visible: parent === layoutsContainer.startLayout
840                 || parent === layoutsContainer.mainLayout
841                 || parent === layoutsContainer.endLayout
842
843        z:1500
844
845        Behavior on length {
846            NumberAnimation {
847                duration: animations.duration.large
848                easing.type: Easing.InQuad
849            }
850        }
851
852        Behavior on opacity {
853            NumberAnimation {
854                duration: animations.duration.large
855                easing.type: Easing.InQuad
856            }
857        }
858
859        Item {
860            id: dndSpacerAddItemContainer
861            width: root.isHorizontal ? parent.length : parent.thickness - metrics.margin.screenEdge
862            height: root.isHorizontal ? parent.thickness - metrics.margin.screenEdge : parent.length
863
864            property int thickMargin: metrics.margin.screenEdge //+ metrics.margin.thickness
865
866            LatteComponents.AddItem{
867                id: dndSpacerAddItem
868                anchors.centerIn: parent
869                width: length
870                height: width
871
872                readonly property int length: Math.min(metrics.iconSize, 96)
873            }
874
875            states:[
876                State{
877                    name: "bottom"
878                    when: plasmoid.location === PlasmaCore.Types.BottomEdge
879
880                    AnchorChanges{
881                        target: dndSpacerAddItemContainer;
882                        anchors.horizontalCenter: parent.horizontalCenter; anchors.verticalCenter: undefined;
883                        anchors.right: undefined; anchors.left: undefined; anchors.top: undefined; anchors.bottom: parent.bottom;
884                    }
885                    PropertyChanges{
886                        target: dndSpacerAddItemContainer;
887                        anchors.leftMargin: 0;    anchors.rightMargin: 0;     anchors.topMargin:0;    anchors.bottomMargin: dndSpacerAddItemContainer.thickMargin;
888                        anchors.horizontalCenterOffset: 0; anchors.verticalCenterOffset: 0;
889                    }
890                },
891                State{
892                    name: "top"
893                    when: plasmoid.location === PlasmaCore.Types.TopEdge
894
895                    AnchorChanges{
896                        target: dndSpacerAddItemContainer;
897                        anchors.horizontalCenter: parent.horizontalCenter; anchors.verticalCenter: undefined;
898                        anchors.right: undefined; anchors.left: undefined; anchors.top: parent.top; anchors.bottom: undefined;
899                    }
900                    PropertyChanges{
901                        target: dndSpacerAddItemContainer;
902                        anchors.leftMargin: 0;    anchors.rightMargin: 0;     anchors.topMargin: dndSpacerAddItemContainer.thickMargin;    anchors.bottomMargin: 0;
903                        anchors.horizontalCenterOffset: 0; anchors.verticalCenterOffset: 0;
904                    }
905                },
906                State{
907                    name: "left"
908                    when: plasmoid.location === PlasmaCore.Types.LeftEdge
909
910                    AnchorChanges{
911                        target: dndSpacerAddItemContainer;
912                        anchors.horizontalCenter: undefined; anchors.verticalCenter: parent.verticalCenter;
913                        anchors.right: undefined; anchors.left: parent.left; anchors.top: undefined; anchors.bottom: undefined;
914                    }
915                    PropertyChanges{
916                        target: dndSpacerAddItemContainer;
917                        anchors.leftMargin: dndSpacerAddItemContainer.thickMargin;    anchors.rightMargin: 0;     anchors.topMargin:0;    anchors.bottomMargin: 0;
918                        anchors.horizontalCenterOffset: 0; anchors.verticalCenterOffset: 0;
919                    }
920                },
921                State{
922                    name: "right"
923                    when: plasmoid.location === PlasmaCore.Types.RightEdge
924
925                    AnchorChanges{
926                        target: dndSpacerAddItemContainer;
927                        anchors.horizontalCenter: undefined; anchors.verticalCenter: parent.verticalCenter;
928                        anchors.right: parent.right; anchors.left: undefined; anchors.top: undefined; anchors.bottom: undefined;
929                    }
930                    PropertyChanges{
931                        target: dndSpacerAddItemContainer;
932                        anchors.leftMargin: 0;    anchors.rightMargin: dndSpacerAddItemContainer.thickMargin;     anchors.topMargin:0;    anchors.bottomMargin: 0;
933                        anchors.horizontalCenterOffset: 0; anchors.verticalCenterOffset: 0;
934                    }
935                }
936            ]
937        }
938    }
939
940    Behavior on maxLengthPerCentage {
941        enabled: root.behaveAsDockWithMask && plasmoid.configuration.floatingGapHidingWaitsMouse && dockContainsMouse
942        NumberAnimation {
943            duration: animations.duration.short
944            easing.type: Easing.InQuad
945        }
946    }
947
948    ///////////////END UI elements
949
950    ///////////////BEGIN ABILITIES
951
952    Ability.Animations {
953        id: _animations
954        layouts: layoutsContainer
955        metrics: _metrics
956        settings: universalSettings
957    }
958
959    Ability.AutoSize {
960        id: _autosize
961        layouts: layoutsContainer
962        layouter: _layouter
963        metrics: _metrics
964        visibility: visibilityManager
965    }
966
967    Ability.Debug {
968        id: _debug
969    }
970
971    AbilityHost.Environment{
972        id: _environment
973    }
974
975    Ability.Indexer {
976        id: _indexer
977        layouts: layoutsContainer
978    }
979
980    Ability.Indicators{
981        id: _indicators
982        view: latteView
983    }
984
985    Ability.Launchers {
986        id: _launchers
987        layouts: layoutsContainer
988        layoutName: latteView && latteView.layout ? latteView.layout.name : ""
989    }
990
991    Ability.Layouter {
992        id: _layouter
993        animations: _animations
994        indexer: _indexer
995        layouts: layoutsContainer
996    }
997
998    Ability.Metrics {
999        id: _metrics
1000        animations: _animations
1001        autosize: _autosize
1002        background: _background
1003        indicators: _indicators
1004        parabolic: _parabolic
1005    }
1006
1007    Ability.MyView {
1008        id: _myView
1009        layouts: layoutsContainer
1010    }
1011
1012    Ability.ParabolicEffect {
1013        id: _parabolic
1014        animations: _animations
1015        debug: _debug
1016        layouts: layoutsContainer
1017        view: latteView
1018    }
1019
1020    Ability.PositionShortcuts {
1021        id: _shortcuts
1022        layouts: layoutsContainer
1023    }
1024
1025    Ability.ThinTooltip {
1026        id: _thinTooltip
1027        debug: _debug
1028        layouts: layoutsContainer
1029        view: latteView
1030    }
1031
1032    Ability.UserRequests {
1033        id: _userRequests
1034        view: latteView
1035    }
1036
1037    LatteApp.Interfaces {
1038        id: _interfaces
1039        plasmoidInterface: plasmoid
1040
1041        Component.onCompleted: {
1042            view.interfacesGraphicObj = _interfaces;
1043        }
1044
1045        onViewChanged: {
1046            if (view) {
1047                view.interfacesGraphicObj = _interfaces;
1048
1049                if (!root.inStartup) {
1050                    //! used from recreating views
1051                    root.inStartup = true;
1052                    startupDelayer.start();
1053                }
1054            }
1055        }
1056    }
1057
1058    ///////////////END ABILITIES
1059
1060    ///////////////BEGIN TIMER elements
1061
1062    //! It is used in order to slide-in the latteView on startup
1063    onInStartupChanged: {
1064        if (!inStartup) {
1065            latteView.positioner.startupFinished();
1066            latteView.positioner.slideInDuringStartup();
1067            visibilityManager.slotMustBeShown();
1068        }
1069    }
1070
1071    Connections {
1072        target:fastLayoutManager
1073        onHasRestoredAppletsChanged: {
1074            if (fastLayoutManager.hasRestoredApplets) {
1075                startupDelayer.start();
1076            }
1077        }
1078    }
1079
1080    Timer {
1081        //! Give a little more time to layouter and applets to load and be positioned properly during startup when
1082        //! the view is drawn out-of-screen and afterwards trigger the startup animation sequence:
1083        //! 1.slide-out when out-of-screen //slotMustBeHide()
1084        //! 2.be positioned properly at correct screen //slideInDuringStartup(), triggers Positioner::syncGeometry()
1085        //! 3.slide-in properly in correct screen //slotMustBeShown();
1086        id: startupDelayer
1087        interval: 1000
1088        onTriggered: {
1089            visibilityManager.slotMustBeHide();
1090        }
1091    }
1092
1093    ///////////////END TIMER elements
1094
1095    Loader{
1096        anchors.fill: parent
1097        active: debug.localGeometryEnabled
1098        sourceComponent: Rectangle{
1099            x: latteView.localGeometry.x
1100            y: latteView.localGeometry.y
1101            //! when view is resized there is a chance that geometry is faulty stacked in old values
1102            width: Math.min(latteView.localGeometry.width, root.width) //! fixes updating
1103            height: Math.min(latteView.localGeometry.height, root.height) //! fixes updating
1104
1105            color: "blue"
1106            border.width: 2
1107            border.color: "red"
1108
1109            opacity: 0.35
1110        }
1111    }
1112
1113    Loader{
1114        anchors.fill: parent
1115        active: latteView && latteView.effects && debug.inputMaskEnabled
1116        sourceComponent: Rectangle{
1117            x: latteView.effects.inputMask.x
1118            y: latteView.effects.inputMask.y
1119            //! when view is resized there is a chance that geometry is faulty stacked in old values
1120            width: Math.min(latteView.effects.inputMask.width, root.width) //! fixes updating
1121            height: Math.min(latteView.effects.inputMask.height, root.height) //! fixes updating
1122
1123            color: "purple"
1124            border.width: 1
1125            border.color: "black"
1126
1127            opacity: 0.20
1128        }
1129    }
1130}
1131