overte-HifiExperiments/interface/resources/qml/windows/Window.qml
2016-01-13 15:40:37 -08:00

188 lines
5.7 KiB
QML

import QtQuick 2.5
import QtQuick.Controls 1.4
import QtGraphicalEffects 1.0
import "."
import "../styles"
FocusScope {
id: window
HifiConstants { id: hifi }
// The Window size is the size of the content, while the frame
// decorations can extend outside it. Windows should generally not be
// given explicit height / width, but rather be allowed to conform to
// their content
implicitHeight: content.height
implicitWidth: content.width
property bool topLevelWindow: true
property string title
// Should the window include a close control?
property bool closable: true
// Should hitting the close button hide or destroy the window?
property bool destroyOnCloseButton: true
// Should hiding the window destroy it or just hide it?
property bool destroyOnInvisible: false
// FIXME support for pinned / unpinned pending full design
// property bool pinnable: false
// property bool pinned: false
property bool resizable: false
property vector2d minSize: Qt.vector2d(100, 100)
property vector2d maxSize: Qt.vector2d(1280, 720)
// The content to place inside the window, determined by the client
default property var content
onContentChanged: {
if (content) {
content.anchors.fill = window
}
}
// Default to a standard frame. Can be overriden to provide custom
// frame styles, like a full desktop frame to simulate a modal window
property var frame: DefaultFrame {
z: -1
anchors.fill: parent
}
// This mouse area serves to raise the window. To function, it must live
// in the window and have a higher Z-order than the content, but follow
// the position and size of frame decoration
property var activator: MouseArea {
width: frame.decoration.width
height: frame.decoration.height
x: frame.decoration.anchors.margins
y: frame.decoration.anchors.topMargin
propagateComposedEvents: true
hoverEnabled: true
onPressed: { window.raise(); mouse.accepted = false; }
// Debugging visualization
// Rectangle { anchors.fill:parent; color: "#7f00ff00" }
}
children: [ frame, content, activator ]
signal windowDestroyed();
Component.onCompleted: {
fadeTargetProperty = visible ? 1.0 : 0.0
raise();
}
Component.onDestruction: {
content.destroy();
console.log("Destroyed " + window);
windowDestroyed();
}
onParentChanged: raise();
Connections {
target: frame
onRaise: window.raise();
onClose: window.close();
onPin: window.pin();
onDeltaSize: {
var newSize = Qt.vector2d(content.width + dx, content.height + dy);
newSize = clampVector(newSize, minSize, maxSize);
window.width = newSize.x
window.height = newSize.y
}
}
function raise() {
if (visible && parent) {
Desktop.raise(window)
if (!focus) {
focus = true;
}
}
}
function pin() {
// pinned = ! pinned
}
// our close function performs the same way as the OffscreenUI class:
// don't do anything but manipulate the targetVisible flag and let the other
// mechanisms decide if the window should be destroyed after the close
// animation completes
function close() {
console.log("Closing " + window)
if (destroyOnCloseButton) {
destroyOnInvisible = true
}
visible = false;
}
//
// Enable window visibility transitions
//
// The target property to animate, usually scale or opacity
property alias fadeTargetProperty: window.opacity
// always start the property at 0 to enable fade in on creation
opacity: 0
// Some dialogs should be destroyed when they become
// invisible, so handle that
onVisibleChanged: {
// If someone directly set the visibility to false
// toggle it back on and use the targetVisible flag to transition
// via fading.
if ((!visible && fadeTargetProperty != 0.0) || (visible && fadeTargetProperty == 0.0)) {
var target = visible;
visible = !visible;
fadeTargetProperty = target ? 1.0 : 0.0;
return;
}
if (!visible && destroyOnInvisible) {
console.log("Destroying " + window);
destroy();
return;
}
}
// The offscreen UI will enable an object, rather than manipulating it's
// visibility, so that we can do animations in both directions. Because
// visibility is a boolean flags, it cannot be animated. So when
// targetVisible is changed, we modify a property that can be animated,
// like scale or opacity, and then when the target animation value is reached,
// we can modify the visibility
// The actual animator
Behavior on fadeTargetProperty {
NumberAnimation {
duration: hifi.effects.fadeInDuration
easing.type: Easing.OutCubic
}
}
// Once we're transparent, disable the dialog's visibility
onFadeTargetPropertyChanged: {
visible = (fadeTargetProperty != 0.0);
}
Keys.onPressed: {
switch(event.key) {
case Qt.Key_W:
if (event.modifiers === Qt.ControlModifier) {
event.accepted = true
visible = false
}
break;
}
}
function clamp(value, min, max) {
return Math.min(Math.max(value, min), max);
}
function clampVector(value, min, max) {
return Qt.vector2d(
clamp(value.x, min.x, max.x),
clamp(value.y, min.y, max.y))
}
}