Merge pull request #7994 from jherico/pinned

Pinned UI support
This commit is contained in:
Howard Stearns 2016-06-03 11:02:59 -07:00
commit af6ec8d8bd
52 changed files with 1082 additions and 1501 deletions

View file

@ -20,9 +20,10 @@ Window {
objectName: "AddressBarDialog"
frame: HiddenFrame {}
hideBackground: true
visible: false
destroyOnInvisible: false
shown: false
destroyOnHidden: false
resizable: false
scale: 1.25 // Make this dialog a little larger than normal
@ -145,14 +146,14 @@ Window {
if (addressLine.text !== "") {
addressBarDialog.loadAddress(addressLine.text)
}
root.visible = false;
root.shown = false;
}
Keys.onPressed: {
switch (event.key) {
case Qt.Key_Escape:
case Qt.Key_Back:
root.visible = false
root.shown = false
event.accepted = true
break
case Qt.Key_Enter:

View file

@ -15,7 +15,7 @@ import Qt.labs.settings 1.0
import "styles-uit"
import "controls-uit" as HifiControls
import "windows-uit"
import "windows"
import "dialogs"
Window {
@ -23,7 +23,7 @@ Window {
objectName: "AssetServer"
title: "Asset Browser"
resizable: true
destroyOnInvisible: true
destroyOnHidden: true
implicitWidth: 384; implicitHeight: 640
minSize: Qt.vector2d(200, 300)

View file

@ -2,8 +2,8 @@ import QtQuick 2.3
import QtQuick.Controls 1.2
import QtWebEngine 1.1
import "controls"
import "styles"
import "controls-uit"
import "styles-uit"
import "windows"
Window {
@ -11,13 +11,15 @@ Window {
HifiConstants { id: hifi }
title: "Browser"
resizable: true
destroyOnInvisible: true
destroyOnHidden: true
width: 800
height: 600
property alias webView: webview
x: 100
y: 100
Component.onCompleted: {
visible = true
shown = true
addressBar.text = webview.url
}
@ -30,14 +32,8 @@ Window {
Item {
id:item
anchors.fill: parent
Rectangle {
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: webview.top
color: "white"
}
width: pane.contentWidth
implicitHeight: pane.scrollHeight
Row {
id: buttons
@ -46,25 +42,37 @@ Window {
anchors.topMargin: 8
anchors.left: parent.left
anchors.leftMargin: 8
FontAwesome {
id: back; text: "\uf0a8"; size: 48; enabled: webview.canGoBack;
HiFiGlyphs {
id: back;
enabled: webview.canGoBack;
text: hifi.glyphs.backward
color: enabled ? hifi.colors.text : hifi.colors.disabledText
size: 48
MouseArea { anchors.fill: parent; onClicked: webview.goBack() }
}
FontAwesome {
id: forward; text: "\uf0a9"; size: 48; enabled: webview.canGoForward;
HiFiGlyphs {
id: forward;
enabled: webview.canGoForward;
text: hifi.glyphs.forward
color: enabled ? hifi.colors.text : hifi.colors.disabledText
MouseArea { anchors.fill: parent; onClicked: webview.goBack() }
size: 48
MouseArea { anchors.fill: parent; onClicked: webview.goForward() }
}
FontAwesome {
id: reload; size: 48; text: webview.loading ? "\uf057" : "\uf021"
MouseArea { anchors.fill: parent; onClicked: webview.loading ? webview.stop() : webview.reload() }
HiFiGlyphs {
id: reload;
enabled: webview.canGoForward;
text: webview.loading ? hifi.glyphs.close : hifi.glyphs.reload
color: enabled ? hifi.colors.text : hifi.colors.disabledText
size: 48
MouseArea { anchors.fill: parent; onClicked: webview.goForward() }
}
}
Border {
Item {
id: border
height: 48
radius: 8
anchors.top: parent.top
anchors.topMargin: 8
anchors.right: parent.right
@ -87,14 +95,17 @@ Window {
}
}
TextInput {
TextField {
id: addressBar
anchors.right: parent.right
anchors.rightMargin: 8
anchors.left: barIcon.right
anchors.leftMargin: 0
anchors.verticalCenter: parent.verticalCenter
focus: true
colorScheme: hifi.colorSchemes.dark
placeholderText: "Enter URL"
Component.onCompleted: scriptsModel.filterRegExp = new RegExp("^.*$", "i")
Keys.onPressed: {
switch(event.key) {
case Qt.Key_Enter:
@ -110,7 +121,7 @@ Window {
}
}
WebView {
WebEngineView {
id: webview
url: "http://highfidelity.com"
anchors.top: buttons.bottom
@ -119,7 +130,7 @@ Window {
anchors.left: parent.left
anchors.right: parent.right
onLoadingChanged: {
if (loadRequest.status == WebEngineView.LoadSucceededStatus) {
if (loadRequest.status === WebEngineView.LoadSucceededStatus) {
addressBar.text = loadRequest.url
}
}
@ -127,7 +138,7 @@ Window {
console.log("New icon: " + icon)
}
profile: desktop.browserProfile
//profile: desktop.browserProfile
}

View file

@ -12,7 +12,7 @@ import QtQuick 2.5
import Hifi 1.0 as Hifi
import "controls-uit"
import "windows-uit" as Windows
import "windows" as Windows
Windows.Window {
id: root

View file

@ -22,8 +22,9 @@ Window {
width: loginDialog.implicitWidth
// FIXME make movable
anchors.centerIn: parent
destroyOnInvisible: false
visible: false
destroyOnHidden: false
hideBackground: true
shown: false
LoginDialog {
id: loginDialog
@ -268,8 +269,8 @@ Window {
}
}
onVisibleChanged: {
if (!visible) {
onShownChanged: {
if (!shown) {
username.text = ""
password.text = ""
loginDialog.statusText = ""
@ -282,7 +283,7 @@ Window {
switch (event.key) {
case Qt.Key_Escape:
case Qt.Key_Back:
root.visible = false;
root.shown = false;
event.accepted = true;
break;

View file

@ -13,7 +13,7 @@ import QtQuick.Controls 1.4
import QtWebEngine 1.1
import QtWebChannel 1.0
import "windows-uit" as Windows
import "windows" as Windows
import "controls-uit" as Controls
import "styles-uit"
@ -22,7 +22,7 @@ Windows.Window {
HifiConstants { id: hifi }
title: "WebWindow"
resizable: true
visible: false
shown: false
// Don't destroy on close... otherwise the JS/C++ will have a dangling pointer
destroyOnCloseButton: false
property alias source: webview.url

View file

@ -14,7 +14,7 @@ Windows.Window {
HifiConstants { id: hifi }
title: "QmlWindow"
resizable: true
visible: false
shown: false
focus: true
property var channel;
// Don't destroy on close... otherwise the JS/C++ will have a dangling pointer

View file

@ -15,7 +15,7 @@ import QtWebEngine 1.1
import QtWebChannel 1.0
import Qt.labs.settings 1.0
import "windows-uit"
import "windows"
import "controls-uit"
import "styles-uit"
@ -24,9 +24,9 @@ Window {
resizable: true
objectName: "ToolWindow"
destroyOnCloseButton: false
destroyOnInvisible: false
destroyOnHidden: false
closable: true
visible: false
shown: false
title: "Edit"
property alias tabView: tabView
implicitWidth: 520; implicitHeight: 695
@ -142,7 +142,7 @@ Window {
return;
}
}
visible = false;
shown = false;
}
function findIndexForUrl(source) {
@ -172,7 +172,7 @@ Window {
var tab = tabView.getTab(index);
if (newVisible) {
toolWindow.visible = true
toolWindow.shown = true
tab.enabled = true
} else {
tab.enabled = false;

View file

@ -3,8 +3,8 @@ import QtQuick 2.3
import QtQuick.Controls 1.3
import QtQuick.Controls.Styles 1.3
import QtGraphicalEffects 1.0
import "controls"
import "styles"
import "controls-uit"
import "styles-uit"
import "windows"
Window {

View file

@ -15,7 +15,7 @@ import QtQuick.XmlListModel 2.0
import "../styles-uit"
import "../controls-uit" as HifiControls
import "../windows-uit"
import "../windows"
import "../hifi/models"
TableView {

View file

@ -52,6 +52,7 @@ FocusScope {
readonly property real menu: 8000
}
QtObject {
id: d
@ -93,6 +94,17 @@ FocusScope {
return item;
}
function findMatchingChildren(item, predicate) {
var results = [];
for (var i in item.children) {
var child = item.children[i];
if (predicate(child)) {
results.push(child);
}
}
return results;
}
function isTopLevelWindow(item) {
return item.topLevelWindow;
}
@ -106,19 +118,9 @@ FocusScope {
}
function getTopLevelWindows(predicate) {
var currentWindows = [];
if (!desktop) {
console.log("Could not find desktop for " + item)
return currentWindows;
}
for (var i = 0; i < desktop.children.length; ++i) {
var child = desktop.children[i];
if (isTopLevelWindow(child) && (!predicate || predicate(child))) {
currentWindows.push(child)
}
}
return currentWindows;
return findMatchingChildren(desktop, function(child) {
return (isTopLevelWindow(child) && (!predicate || predicate(child)));
});
}
function getDesktopWindow(item) {
@ -227,19 +229,9 @@ FocusScope {
}
function getRepositionChildren(predicate) {
var currentWindows = [];
if (!desktop) {
console.log("Could not find desktop");
return currentWindows;
}
for (var i = 0; i < desktop.children.length; ++i) {
var child = desktop.children[i];
if (child.shouldReposition === true && (!predicate || predicate(child))) {
currentWindows.push(child)
}
}
return currentWindows;
return findMatchingChildren(desktop, function(child) {
return (child.shouldReposition === true && (!predicate || predicate(child)));
});
}
function repositionAll() {
@ -265,6 +257,60 @@ FocusScope {
}
}
property bool pinned: false
property var hiddenChildren: []
function togglePinned() {
pinned = !pinned
}
function setPinned(newPinned) {
pinned = newPinned
}
property real unpinnedAlpha: 1.0;
Behavior on unpinnedAlpha {
NumberAnimation {
easing.type: Easing.Linear;
duration: 300
}
}
state: "NORMAL"
states: [
State {
name: "NORMAL"
PropertyChanges { target: desktop; unpinnedAlpha: 1.0 }
},
State {
name: "PINNED"
PropertyChanges { target: desktop; unpinnedAlpha: 0.0 }
}
]
transitions: [
Transition {
NumberAnimation { properties: "unpinnedAlpha"; duration: 300 }
}
]
onPinnedChanged: {
if (pinned) {
// recalculate our non-pinned children
hiddenChildren = d.findMatchingChildren(desktop, function(child){
return !d.isTopLevelWindow(child) && child.visible;
});
hiddenChildren.forEach(function(child){
child.opacity = Qt.binding(function(){ return desktop.unpinnedAlpha });
});
}
state = pinned ? "PINNED" : "NORMAL"
}
onShowDesktop: pinned = false
function raise(item) {
var targetWindow = d.getDesktopWindow(item);
if (!targetWindow) {
@ -422,7 +468,6 @@ FocusScope {
event.accepted = false;
}
function unfocusWindows() {
var windows = d.getTopLevelWindows();
for (var i = 0; i < windows.length; ++i) {

View file

@ -18,7 +18,7 @@ import QtQuick.Dialogs 1.2 as OriginalDialogs
import ".."
import "../controls-uit"
import "../styles-uit"
import "../windows-uit"
import "../windows"
import "fileDialog"
@ -724,7 +724,7 @@ ModalWindow {
Action {
id: cancelAction
text: "Cancel"
onTriggered: { canceled(); root.visible = false; }
onTriggered: { canceled(); root.shown = false; }
}
}

View file

@ -14,7 +14,7 @@ import QtQuick.Dialogs 1.2 as OriginalDialogs
import "../controls-uit"
import "../styles-uit"
import "../windows-uit"
import "../windows"
import "messageDialog"
@ -24,7 +24,7 @@ ModalWindow {
implicitWidth: 640
implicitHeight: 320
destroyOnCloseButton: true
destroyOnInvisible: true
destroyOnHidden: true
visible: true
signal selected(int button);

View file

@ -13,14 +13,14 @@ import QtQuick.Controls 1.4
import "../controls-uit" as HifiControls
import "../styles-uit"
import "../windows-uit"
import "../windows"
import "preferences"
Window {
id: root
title: "Preferences"
resizable: true
destroyOnInvisible: true
destroyOnHidden: true
width: 500
height: 577
property var sections: []

View file

@ -14,7 +14,7 @@ import QtQuick.Dialogs 1.2 as OriginalDialogs
import "../controls-uit"
import "../styles-uit"
import "../windows-uit"
import "../windows"
ModalWindow {
id: root

View file

@ -12,7 +12,7 @@ import QtQuick 2.5
import QtQuick.Controls 1.4
import QtWebEngine 1.1
import "../../windows-uit" as Windows
import "../../windows" as Windows
import "../../controls-uit" as Controls
import "../../styles-uit"

View file

@ -6,7 +6,7 @@ import QtQuick.Controls.Styles 1.4
import "../../styles-uit"
import "../../controls-uit" as HifiControls
import "../../windows-uit"
import "../../windows"
import "attachments"
Window {
@ -16,7 +16,7 @@ Window {
width: 600
height: 600
resizable: true
destroyOnInvisible: true
destroyOnHidden: true
minSize: Qt.vector2d(400, 500)
HifiConstants { id: hifi }

View file

@ -9,7 +9,7 @@ import "../models"
import "../../styles-uit"
import "../../controls-uit" as HifiControls
import "../../windows-uit"
import "../../windows"
Window {
id: root

View file

@ -15,14 +15,14 @@ import Qt.labs.settings 1.0
import "../../styles-uit"
import "../../controls-uit" as HifiControls
import "../../windows-uit"
import "../../windows"
Window {
id: root
objectName: "RunningScripts"
title: "Running Scripts"
resizable: true
destroyOnInvisible: true
destroyOnHidden: true
implicitWidth: 400
implicitHeight: isHMD ? 695 : 728
minSize: Qt.vector2d(200, 300)
@ -34,6 +34,9 @@ Window {
property var runningScriptsModel: ListModel { }
property bool isHMD: false
onVisibleChanged: console.log("Running scripts visible changed to " + visible)
onShownChanged: console.log("Running scripts visible changed to " + visible)
Settings {
category: "Overlay.RunningScripts"
property alias x: root.x

View file

@ -8,7 +8,7 @@ import "."
import ".."
import "../../../styles-uit"
import "../../../controls-uit" as HifiControls
import "../../../windows-uit"
import "../../../windows"
Item {
height: column.height + 2 * 8

View file

@ -3,7 +3,7 @@ import QtQuick.Controls 1.4
import "../../../styles-uit"
import "../../../controls-uit" as HifiControls
import "../../../windows-uit"
import "../../../windows"
Item {
id: root

View file

@ -1,119 +0,0 @@
//
// DefaultFrame.qml
//
// Created by Bradley Austin Davis on 12 Jan 2016
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtGraphicalEffects 1.0
import "."
import "../styles-uit"
Frame {
HifiConstants { id: hifi }
Rectangle {
// Dialog frame
id: frameContent
readonly property int iconSize: hifi.dimensions.frameIconSize
readonly property int frameMargin: 9
readonly property int frameMarginLeft: frameMargin
readonly property int frameMarginRight: frameMargin
readonly property int frameMarginTop: 2 * frameMargin + iconSize
readonly property int frameMarginBottom: iconSize + 11
anchors {
topMargin: -frameMarginTop
leftMargin: -frameMarginLeft
rightMargin: -frameMarginRight
bottomMargin: -frameMarginBottom
}
anchors.fill: parent
color: hifi.colors.baseGrayHighlight40
border {
width: hifi.dimensions.borderWidth
color: hifi.colors.faintGray50
}
radius: hifi.dimensions.borderRadius
// Enable dragging of the window
MouseArea {
anchors.fill: parent
drag.target: window
}
Row {
id: controlsRow
anchors {
right: parent.right;
top: parent.top;
topMargin: frameContent.frameMargin + 1 // Move down a little to visually align with the title
rightMargin: frameContent.frameMarginRight;
}
spacing: frameContent.iconSize / 4
HiFiGlyphs {
// "Pin" button
visible: false
text: (frame.pinned && !pinClickArea.containsMouse) || (!frame.pinned && pinClickArea.containsMouse) ? hifi.glyphs.pinInverted : hifi.glyphs.pin
color: pinClickArea.containsMouse && !pinClickArea.pressed ? hifi.colors.redHighlight : hifi.colors.white
size: frameContent.iconSize
MouseArea {
id: pinClickArea
anchors.fill: parent
hoverEnabled: true
propagateComposedEvents: true
onClicked: { frame.pin(); mouse.accepted = false; }
}
}
HiFiGlyphs {
// "Close" button
visible: window ? window.closable : false
text: closeClickArea.containsPress ? hifi.glyphs.closeInverted : hifi.glyphs.close
color: closeClickArea.containsMouse ? hifi.colors.redHighlight : hifi.colors.white
size: frameContent.iconSize
MouseArea {
id: closeClickArea
anchors.fill: parent
hoverEnabled: true
onClicked: window.visible = false;
}
}
}
RalewayRegular {
// Title
id: titleText
anchors {
left: parent.left
leftMargin: frameContent.frameMarginLeft + hifi.dimensions.contentMargin.x
right: controlsRow.left
rightMargin: frameContent.iconSize
top: parent.top
topMargin: frameContent.frameMargin
}
text: window ? window.title : ""
color: hifi.colors.white
size: hifi.fontSizes.overlayTitle
}
DropShadow {
source: titleText
anchors.fill: titleText
horizontalOffset: 2
verticalOffset: 2
samples: 2
color: hifi.colors.baseGrayShadow60
visible: (window && window.focus)
cached: true
}
}
}

View file

@ -1,60 +0,0 @@
//
// Fadable.qml
//
// Created by Bradley Austin Davis on 15 Jan 2016
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtGraphicalEffects 1.0
import "../styles-uit"
// Enable window visibility transitions
FocusScope {
id: root
HifiConstants { id: hifi }
Component.onCompleted: {
fadeTargetProperty = visible ? 1.0 : 0.0
}
// The target property to animate, usually scale or opacity
property alias fadeTargetProperty: root.opacity
// always start the property at 0 to enable fade in on creation
fadeTargetProperty: 0
// DO NOT set visible to false or when derived types override it it
// will short circuit the fade in on initial visibility
// visible: false <--- NO
// 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;
}
}
// The actual animator
Behavior on fadeTargetProperty {
NumberAnimation {
duration: hifi.effects.fadeInDuration
easing.type: Easing.InOutCubic
}
}
// Once we're transparent, disable the dialog's visibility
onFadeTargetPropertyChanged: {
visible = (fadeTargetProperty != 0.0);
}
}

View file

@ -1,133 +0,0 @@
//
// Frame.qml
//
// Created by Bradley Austin Davis on 12 Jan 2016
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtGraphicalEffects 1.0
import "../styles-uit"
import "../js/Utils.js" as Utils
Item {
id: frame
HifiConstants { id: hifi }
default property var decoration
property bool gradientsSupported: desktop.gradientsSupported
readonly property int frameMarginLeft: frameContent.frameMarginLeft
readonly property int frameMarginRight: frameContent.frameMarginRight
readonly property int frameMarginTop: frameContent.frameMarginTop
readonly property int frameMarginBottom: frameContent.frameMarginBottom
// Frames always fill their parents, but their decorations may extend
// beyond the window via negative margin sizes
anchors.fill: parent
children: [
focusShadow,
decoration,
sizeOutline,
debugZ,
sizeDrag
]
Text {
id: debugZ
visible: DebugQML
text: window ? "Z: " + window.z : ""
y: window ? window.height + 4 : 0
}
function deltaSize(dx, dy) {
var newSize = Qt.vector2d(window.width + dx, window.height + dy);
newSize = Utils.clampVector(newSize, window.minSize, window.maxSize);
window.width = newSize.x
window.height = newSize.y
}
RadialGradient {
id: focusShadow
width: 1.66 * window.width
height: 1.66 * window.height
x: (window.width - width) / 2
y: window.height / 2 - 0.375 * height
visible: gradientsSupported && window && window.focus && pane.visible
gradient: Gradient {
// GradientStop position 0.5 is at full circumference of circle that fits inside the square.
GradientStop { position: 0.0; color: "#ff000000" } // black, 100% opacity
GradientStop { position: 0.333; color: "#1f000000" } // black, 12% opacity
GradientStop { position: 0.5; color: "#00000000" } // black, 0% opacity
GradientStop { position: 1.0; color: "#00000000" }
}
cached: true
}
Rectangle {
id: sizeOutline
x: -frameMarginLeft
y: -frameMarginTop
width: window ? window.width + frameMarginLeft + frameMarginRight + 2 : 0
height: window ? window.height + frameMarginTop + frameMarginBottom + 2 : 0
color: hifi.colors.baseGrayHighlight15
border.width: 3
border.color: hifi.colors.white50
radius: hifi.dimensions.borderRadius
visible: window ? !pane.visible : false
}
MouseArea {
// Resize handle
id: sizeDrag
width: hifi.dimensions.frameIconSize
height: hifi.dimensions.frameIconSize
enabled: window ? window.resizable : false
hoverEnabled: true
x: window ? window.width + frameMarginRight - hifi.dimensions.frameIconSize : 0
y: window ? window.height + 4 : 0
property vector2d pressOrigin
property vector2d sizeOrigin
property bool hid: false
onPressed: {
//console.log("Pressed on size")
pressOrigin = Qt.vector2d(mouseX, mouseY)
sizeOrigin = Qt.vector2d(window.content.width, window.content.height)
hid = false;
}
onReleased: {
if (hid) {
pane.visible = true
frameContent.visible = true
hid = false;
}
}
onPositionChanged: {
if (pressed) {
if (pane.visible) {
pane.visible = false;
frameContent.visible = false
hid = true;
}
var delta = Qt.vector2d(mouseX, mouseY).minus(pressOrigin);
frame.deltaSize(delta.x, delta.y)
}
}
HiFiGlyphs {
visible: sizeDrag.enabled
x: -11 // Move a little to visually align
y: window.modality == Qt.ApplicationModal ? -6 : -4
text: hifi.glyphs.resizeHandle
size: hifi.dimensions.frameIconSize + 10
color: sizeDrag.containsMouse || sizeDrag.pressed
? hifi.colors.white
: (window.colorScheme == hifi.colorSchemes.dark ? hifi.colors.white50 : hifi.colors.lightGrayText80)
}
}
}

View file

@ -1,98 +0,0 @@
//
// ModalFrame.qml
//
// Created by Bradley Austin Davis on 15 Jan 2016
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import "."
import "../controls-uit"
import "../styles-uit"
Frame {
HifiConstants { id: hifi }
Rectangle {
id: frameContent
readonly property bool hasTitle: window.title != ""
readonly property int frameMarginLeft: hifi.dimensions.modalDialogMargin.x
readonly property int frameMarginRight: hifi.dimensions.modalDialogMargin.x
readonly property int frameMarginTop: hifi.dimensions.modalDialogMargin.y + (frameContent.hasTitle ? hifi.dimensions.modalDialogTitleHeight + 10 : 0)
readonly property int frameMarginBottom: hifi.dimensions.modalDialogMargin.y
signal frameClicked();
anchors {
fill: parent
topMargin: -frameMarginTop
leftMargin: -frameMarginLeft
rightMargin: -frameMarginRight
bottomMargin: -frameMarginBottom
}
border {
width: hifi.dimensions.borderWidth
color: hifi.colors.lightGrayText80
}
radius: hifi.dimensions.borderRadius
color: hifi.colors.faintGray
// Enable dragging of the window
MouseArea {
anchors.fill: parent
drag.target: window
enabled: window.draggable
onClicked: window.frameClicked();
}
Item {
visible: frameContent.hasTitle
anchors.fill: parent
anchors {
topMargin: -parent.anchors.topMargin
leftMargin: -parent.anchors.leftMargin
rightMargin: -parent.anchors.rightMargin
}
Item {
width: title.width + (icon.text !== "" ? icon.width + hifi.dimensions.contentSpacing.x : 0)
x: (parent.width - width) / 2
onWidthChanged: window.titleWidth = width
HiFiGlyphs {
id: icon
text: window.iconText ? window.iconText : ""
size: window.iconSize ? window.iconSize : 30
color: hifi.colors.lightGray
visible: text != ""
anchors.verticalCenter: title.verticalCenter
anchors.left: parent.left
}
RalewayRegular {
id: title
text: window.title
elide: Text.ElideRight
color: hifi.colors.baseGrayHighlight
size: hifi.fontSizes.overlayTitle
y: -hifi.dimensions.modalDialogTitleHeight
anchors.right: parent.right
}
}
Rectangle {
anchors.left: parent.left
anchors.right: parent.right
height: 1
color: hifi.colors.lightGray
}
}
}
}

View file

@ -1,28 +0,0 @@
//
// ModalWindow.qml
//
// Created by Bradley Austin Davis on 22 Jan 2016
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import "."
Window {
id: window
modality: Qt.ApplicationModal
destroyOnCloseButton: true
destroyOnInvisible: true
frame: ModalFrame { }
property int colorScheme: hifi.colorSchemes.light
property bool draggable: false
signal frameClicked();
anchors.centerIn: draggable ? undefined : parent
}

View file

@ -1,343 +0,0 @@
//
// Window.qml
//
// Created by Bradley Austin Davis on 12 Jan 2016
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtGraphicalEffects 1.0
import "."
import "../styles-uit"
// FIXME how do I set the initial position of a window without
// overriding places where the a individual client of the window
// might be setting the position with a Settings{} element?
// FIXME how to I enable dragging without allowing the window to lay outside
// of the desktop? How do I ensure when the desktop resizes all the windows
// are still at least partially visible?
Fadable {
id: window
HifiConstants { id: hifi }
// The Window size is the size of the content, while the frame
// decorations can extend outside it.
implicitHeight: content ? content.height : 0
implicitWidth: content ? content.width : 0
x: desktop.invalid_position; y: desktop.invalid_position;
enabled: visible
signal windowDestroyed();
property int modality: Qt.NonModal
readonly property bool topLevelWindow: true
property string title
// Should the window be closable control?
property bool closable: true
// Should the window try to remain on top of other windows?
property bool alwaysOnTop: false
// 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 bool gradientsSupported: desktop.gradientsSupported
property int colorScheme: hifi.colorSchemes.dark
property vector2d minSize: Qt.vector2d(100, 100)
property vector2d maxSize: Qt.vector2d(1280, 800)
// The content to place inside the window, determined by the client
default property var content
property var footer: Item { } // Optional static footer at the bottom of the dialog.
function setDefaultFocus() {} // Default function; can be overridden by dialogs.
property var rectifier: Timer {
property bool executing: false;
interval: 100
repeat: false
running: false
onTriggered: {
executing = true;
x = Math.floor(x);
y = Math.floor(y);
executing = false;
}
function begin() {
if (!executing) {
restart();
}
}
}
onXChanged: rectifier.begin();
onYChanged: rectifier.begin();
// 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.leftMargin
y: frame.decoration.anchors.topMargin
propagateComposedEvents: true
acceptedButtons: Qt.AllButtons
enabled: window.visible
onPressed: {
//console.log("Pressed on activator area");
window.raise();
mouse.accepted = false;
}
}
// This mouse area serves to swallow mouse events while the mouse is over the window
// to prevent things like mouse wheel events from reaching the application and changing
// the camera if the user is scrolling through a list and gets to the end.
property var swallower: MouseArea {
width: frame.decoration.width
height: frame.decoration.height
x: frame.decoration.anchors.leftMargin
y: frame.decoration.anchors.topMargin
hoverEnabled: true
acceptedButtons: Qt.AllButtons
enabled: window.visible
onClicked: {}
onDoubleClicked: {}
onPressAndHold: {}
onReleased: {}
onWheel: {}
}
// 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 { }
// Scrollable window content.
property var pane: Item {
property bool isScrolling: scrollView.height < scrollView.contentItem.height
property int contentWidth: scrollView.width - (isScrolling ? 10 : 0)
property int scrollHeight: scrollView.height
anchors.fill: parent
anchors.rightMargin: isScrolling ? 11 : 0
Rectangle {
id: contentBackground
anchors.fill: parent
anchors.rightMargin: parent.isScrolling ? 11 : 0
color: hifi.colors.baseGray
visible: modality != Qt.ApplicationModal
}
LinearGradient {
visible: gradientsSupported && modality != Qt.ApplicationModal
anchors.top: contentBackground.bottom
anchors.left: contentBackground.left
width: contentBackground.width - 1
height: 4
start: Qt.point(0, 0)
end: Qt.point(0, 4)
gradient: Gradient {
GradientStop { position: 0.0; color: hifi.colors.darkGray }
GradientStop { position: 1.0; color: hifi.colors.darkGray0 }
}
cached: true
}
ScrollView {
id: scrollView
contentItem: content
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
verticalScrollBarPolicy: Qt.ScrollBarAsNeeded
anchors.fill: parent
anchors.rightMargin: parent.isScrolling ? 1 : 0
anchors.bottomMargin: footer.height > 0 ? footerPane.height : 0
style: ScrollViewStyle {
padding.right: -7 // Move to right away from content.
handle: Item {
implicitWidth: 8
Rectangle {
radius: 4
color: hifi.colors.white30
anchors {
fill: parent
leftMargin: 2 // Finesse size and position.
topMargin: 1
bottomMargin: 1
}
}
}
scrollBarBackground: Item {
implicitWidth: 10
Rectangle {
color: hifi.colors.darkGray30
radius: 4
anchors {
fill: parent
topMargin: -1 // Finesse size
bottomMargin: -2
}
}
}
incrementControl: Item {
visible: false
}
decrementControl: Item {
visible: false
}
}
}
Rectangle {
// Optional non-scrolling footer.
id: footerPane
anchors {
left: parent.left
bottom: parent.bottom
}
width: parent.contentWidth
height: footer.height + 2 * hifi.dimensions.contentSpacing.y + 3
color: hifi.colors.baseGray
visible: footer.height > 0
Item {
// Horizontal rule.
anchors.fill: parent
Rectangle {
width: parent.width
height: 1
y: 1 // Stop displaying content just above horizontal rule/=.
color: hifi.colors.baseGrayShadow
}
Rectangle {
width: parent.width
height: 1
y: 2
color: hifi.colors.baseGrayHighlight
}
}
Item {
anchors.fill: parent
anchors.topMargin: 3 // Horizontal rule.
children: [ footer ]
}
}
}
children: [ swallower, frame, pane, activator ]
Component.onCompleted: {
window.parentChanged.connect(raise);
raise();
setDefaultFocus();
centerOrReposition();
}
Component.onDestruction: {
window.parentChanged.disconnect(raise); // Prevent warning on shutdown
windowDestroyed();
}
onVisibleChanged: {
if (!visible && destroyOnInvisible) {
destroy();
return;
}
if (visible) {
raise();
}
enabled = visible
if (visible && parent) {
centerOrReposition();
}
}
function centerOrReposition() {
if (x == desktop.invalid_position && y == desktop.invalid_position) {
desktop.centerOnVisible(window);
} else {
desktop.repositionOnVisible(window);
}
}
function raise() {
if (visible && parent) {
desktop.raise(window)
}
}
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
// FIXME using this close function messes up the visibility signals received by the
// type and it's derived types
// function close() {
// console.log("Closing " + window)
// if (destroyOnCloseButton) {
// destroyOnInvisible = true
// }
// visible = false;
// }
function framedRect() {
if (!frame || !frame.decoration) {
return Qt.rect(0, 0, window.width, window.height)
}
return Qt.rect(frame.decoration.anchors.leftMargin, frame.decoration.anchors.topMargin,
window.width - frame.decoration.anchors.leftMargin - frame.decoration.anchors.rightMargin,
window.height - frame.decoration.anchors.topMargin - frame.decoration.anchors.bottomMargin)
}
Keys.onPressed: {
switch(event.key) {
case Qt.Key_Control:
case Qt.Key_Shift:
case Qt.Key_Meta:
case Qt.Key_Alt:
break;
case Qt.Key_W:
if (window.closable && (event.modifiers === Qt.ControlModifier)) {
visible = false
event.accepted = true
}
// fall through
default:
// Consume unmodified keyboard entries while the window is focused, to prevent them
// from propagating to the application
if (event.modifiers === Qt.NoModifier) {
event.accepted = true;
}
break;
}
}
}

View file

@ -1,20 +1,48 @@
//
// DefaultFrame.qml
//
// Created by Bradley Austin Davis on 12 Jan 2016
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtGraphicalEffects 1.0
import "."
import "../controls"
import "../styles-uit"
Frame {
id: frame
property bool wideTopMargin: (window && (window.closable || window.title));
HifiConstants { id: hifi }
Rectangle {
anchors { margins: -iconSize; topMargin: -iconSize * (wideTopMargin ? 2 : 1); }
anchors.fill: parent;
color: "#7f7f7f7f";
radius: 3;
// Dialog frame
id: frameContent
// Allow dragging of the window
readonly property int iconSize: hifi.dimensions.frameIconSize
readonly property int frameMargin: 9
readonly property int frameMarginLeft: frameMargin
readonly property int frameMarginRight: frameMargin
readonly property int frameMarginTop: 2 * frameMargin + iconSize
readonly property int frameMarginBottom: iconSize + 11
anchors {
topMargin: -frameMarginTop
leftMargin: -frameMarginLeft
rightMargin: -frameMarginRight
bottomMargin: -frameMarginBottom
}
anchors.fill: parent
color: hifi.colors.baseGrayHighlight40
border {
width: hifi.dimensions.borderWidth
color: hifi.colors.faintGray50
}
radius: hifi.dimensions.borderRadius
// Enable dragging of the window
MouseArea {
anchors.fill: parent
drag.target: window
@ -22,48 +50,70 @@ Frame {
Row {
id: controlsRow
anchors { right: parent.right; top: parent.top; rightMargin: iconSize; topMargin: iconSize / 2; }
spacing: iconSize / 4
FontAwesome {
visible: false
text: "\uf08d"
style: Text.Outline; styleColor: "white"
size: frame.iconSize
rotation: !frame.parent ? 90 : frame.parent.pinned ? 0 : 90
color: frame.pinned ? "red" : "black"
anchors {
right: parent.right;
top: parent.top;
topMargin: frameContent.frameMargin + 1 // Move down a little to visually align with the title
rightMargin: frameContent.frameMarginRight;
}
spacing: frameContent.iconSize / 4
HiFiGlyphs {
// "Pin" button
visible: window.pinnable
text: window.pinned ? hifi.glyphs.pinInverted : hifi.glyphs.pin
color: pinClickArea.pressed ? hifi.colors.redHighlight : hifi.colors.white
size: frameContent.iconSize
MouseArea {
id: pinClickArea
anchors.fill: parent
hoverEnabled: true
propagateComposedEvents: true
onClicked: { frame.pin(); mouse.accepted = false; }
onClicked: window.pinned = !window.pinned;
}
}
FontAwesome {
HiFiGlyphs {
// "Close" button
visible: window ? window.closable : false
text: closeClickArea.containsMouse ? "\uf057" : "\uf05c"
style: Text.Outline;
styleColor: "white"
color: closeClickArea.containsMouse ? "red" : "black"
size: frame.iconSize
text: closeClickArea.containsPress ? hifi.glyphs.closeInverted : hifi.glyphs.close
color: closeClickArea.containsMouse ? hifi.colors.redHighlight : hifi.colors.white
size: frameContent.iconSize
MouseArea {
id: closeClickArea
anchors.fill: parent
hoverEnabled: true
onClicked: window.visible = false;
onClicked: window.shown = false;
}
}
}
Text {
RalewayRegular {
// Title
id: titleText
anchors { left: parent.left; leftMargin: iconSize; right: controlsRow.left; rightMargin: iconSize; top: parent.top; topMargin: iconSize / 2; }
text: window ? window.title : ""
elide: Text.ElideRight
font.bold: true
color: (window && window.focus) ? "white" : "gray"
style: Text.Outline;
styleColor: "black"
anchors {
left: parent.left
leftMargin: frameContent.frameMarginLeft + hifi.dimensions.contentMargin.x
right: controlsRow.left
rightMargin: frameContent.iconSize
top: parent.top
topMargin: frameContent.frameMargin
}
text: window ? window.title : ""
color: hifi.colors.white
size: hifi.fontSizes.overlayTitle
}
DropShadow {
source: titleText
anchors.fill: titleText
horizontalOffset: 2
verticalOffset: 2
samples: 2
color: hifi.colors.baseGrayShadow60
visible: (window && window.focus)
cached: true
}
}
}

View file

@ -1,8 +1,18 @@
//
// Fadable.qml
//
// Created by Bradley Austin Davis on 15 Jan 2016
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtGraphicalEffects 1.0
import "."
import "../styles"
import "../styles-uit"
// Enable window visibility transitions
FocusScope {
@ -13,6 +23,7 @@ FocusScope {
fadeTargetProperty = visible ? 1.0 : 0.0
}
property var completionCallback;
// The target property to animate, usually scale or opacity
property alias fadeTargetProperty: root.opacity
// always start the property at 0 to enable fade in on creation
@ -33,6 +44,13 @@ FocusScope {
fadeTargetProperty = target ? 1.0 : 0.0;
return;
}
// Now handle completions
if (completionCallback) {
completionCallback();
completionCallback = undefined;
}
}
// The actual animator
@ -43,8 +61,17 @@ FocusScope {
}
}
// Once we're transparent, disable the dialog's visibility
onFadeTargetPropertyChanged: {
visible = (fadeTargetProperty != 0.0);
}
function fadeIn(callback) {
completionCallback = callback;
fadeTargetProperty = 1.0;
}
function fadeOut(callback) {
completionCallback = callback;
fadeTargetProperty = 0.0;
}
}

View file

@ -1,24 +1,42 @@
import QtQuick 2.5
//
// Frame.qml
//
// Created by Bradley Austin Davis on 12 Jan 2016
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import "../controls"
import QtQuick 2.5
import QtGraphicalEffects 1.0
import "../styles-uit"
import "../js/Utils.js" as Utils
Item {
id: frame
HifiConstants { id: hifi }
default property var decoration
property bool gradientsSupported: desktop.gradientsSupported
readonly property int frameMarginLeft: frameContent.frameMarginLeft
readonly property int frameMarginRight: frameContent.frameMarginRight
readonly property int frameMarginTop: frameContent.frameMarginTop
readonly property int frameMarginBottom: frameContent.frameMarginBottom
// Frames always fill their parents, but their decorations may extend
// beyond the window via negative margin sizes
anchors.fill: parent
// Convenience accessor for the window
property alias window: frame.parent
readonly property int iconSize: 24
default property var decoration;
children: [
focusShadow,
decoration,
sizeOutline,
debugZ,
sizeDrag,
sizeDrag
]
Text {
@ -35,57 +53,81 @@ Item {
window.height = newSize.y
}
RadialGradient {
id: focusShadow
width: 1.66 * window.width
height: 1.66 * window.height
x: (window.width - width) / 2
y: window.height / 2 - 0.375 * height
visible: gradientsSupported && window && window.focus && pane.visible
gradient: Gradient {
// GradientStop position 0.5 is at full circumference of circle that fits inside the square.
GradientStop { position: 0.0; color: "#ff000000" } // black, 100% opacity
GradientStop { position: 0.333; color: "#1f000000" } // black, 12% opacity
GradientStop { position: 0.5; color: "#00000000" } // black, 0% opacity
GradientStop { position: 1.0; color: "#00000000" }
}
cached: true
}
Rectangle {
id: sizeOutline
width: window ? window.width : 0
height: window ? window.height : 0
color: "#00000000"
border.width: 4
radius: 10
visible: window ? !window.content.visible : false
x: -frameMarginLeft
y: -frameMarginTop
width: window ? window.width + frameMarginLeft + frameMarginRight + 2 : 0
height: window ? window.height + frameMarginTop + frameMarginBottom + 2 : 0
color: hifi.colors.baseGrayHighlight15
border.width: 3
border.color: hifi.colors.white50
radius: hifi.dimensions.borderRadius
visible: window ? !pane.visible : false
}
MouseArea {
// Resize handle
id: sizeDrag
width: iconSize
height: iconSize
width: hifi.dimensions.frameIconSize
height: hifi.dimensions.frameIconSize
enabled: window ? window.resizable : false
x: window ? window.width : 0
y: window ? window.height : 0
hoverEnabled: true
x: window ? window.width + frameMarginRight - hifi.dimensions.frameIconSize : 0
y: window ? window.height + 4 : 0
property vector2d pressOrigin
property vector2d sizeOrigin
property bool hid: false
onPressed: {
console.log("Pressed on size")
//console.log("Pressed on size")
pressOrigin = Qt.vector2d(mouseX, mouseY)
sizeOrigin = Qt.vector2d(window.content.width, window.content.height)
hid = false;
}
onReleased: {
if (hid) {
window.content.visible = true
pane.visible = true
frameContent.visible = true
hid = false;
}
}
onPositionChanged: {
if (pressed) {
if (window.content.visible) {
window.content.visible = false;
if (pane.visible) {
pane.visible = false;
frameContent.visible = false
hid = true;
}
var delta = Qt.vector2d(mouseX, mouseY).minus(pressOrigin);
frame.deltaSize(delta.x, delta.y)
}
}
FontAwesome {
HiFiGlyphs {
visible: sizeDrag.enabled
rotation: -45
anchors { centerIn: parent }
horizontalAlignment: Text.AlignHCenter
text: "\uf07d"
size: iconSize / 3 * 2
style: Text.Outline; styleColor: "white"
x: -11 // Move a little to visually align
y: window.modality == Qt.ApplicationModal ? -6 : -4
text: hifi.glyphs.resizeHandle
size: hifi.dimensions.frameIconSize + 10
color: sizeDrag.containsMouse || sizeDrag.pressed
? hifi.colors.white
: (window.colorScheme == hifi.colorSchemes.dark ? hifi.colors.white50 : hifi.colors.lightGrayText80)
}
}
}

View file

@ -2,7 +2,7 @@ import QtQuick 2.5
import "."
Frame {
Item {
id: frame
Item { anchors.fill: parent }

View file

@ -1,36 +1,98 @@
//
// ModalFrame.qml
//
// Created by Bradley Austin Davis on 15 Jan 2016
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import "."
import "../controls"
import "../controls-uit"
import "../styles-uit"
Frame {
id: frame
Item {
anchors.fill: parent
HifiConstants { id: hifi }
Rectangle {
id: background
anchors.fill: parent
anchors.margins: -4096
visible: window.visible
color: "#7f7f7f7f";
radius: 3;
id: frameContent
readonly property bool hasTitle: window.title != ""
readonly property int frameMarginLeft: hifi.dimensions.modalDialogMargin.x
readonly property int frameMarginRight: hifi.dimensions.modalDialogMargin.x
readonly property int frameMarginTop: hifi.dimensions.modalDialogMargin.y + (frameContent.hasTitle ? hifi.dimensions.modalDialogTitleHeight + 10 : 0)
readonly property int frameMarginBottom: hifi.dimensions.modalDialogMargin.y
signal frameClicked();
anchors {
fill: parent
topMargin: -frameMarginTop
leftMargin: -frameMarginLeft
rightMargin: -frameMarginRight
bottomMargin: -frameMarginBottom
}
Text {
y: -implicitHeight - iconSize / 2
border {
width: hifi.dimensions.borderWidth
color: hifi.colors.lightGrayText80
}
radius: hifi.dimensions.borderRadius
color: hifi.colors.faintGray
// Enable dragging of the window
MouseArea {
anchors.fill: parent
drag.target: window
enabled: window.draggable
onClicked: window.frameClicked();
}
Item {
visible: frameContent.hasTitle
anchors.fill: parent
anchors {
topMargin: -parent.anchors.topMargin
leftMargin: -parent.anchors.leftMargin
rightMargin: -parent.anchors.rightMargin
}
Item {
width: title.width + (icon.text !== "" ? icon.width + hifi.dimensions.contentSpacing.x : 0)
x: (parent.width - width) / 2
onWidthChanged: window.titleWidth = width
HiFiGlyphs {
id: icon
text: window.iconText ? window.iconText : ""
size: window.iconSize ? window.iconSize : 30
color: hifi.colors.lightGray
visible: text != ""
anchors.verticalCenter: title.verticalCenter
anchors.left: parent.left
}
RalewayRegular {
id: title
text: window.title
elide: Text.ElideRight
font.bold: true
color: window.focus ? "white" : "gray"
style: Text.Outline;
styleColor: "black"
color: hifi.colors.baseGrayHighlight
size: hifi.fontSizes.overlayTitle
y: -hifi.dimensions.modalDialogTitleHeight
anchors.right: parent.right
}
}
Rectangle {
anchors.left: parent.left
anchors.right: parent.right
height: 1
color: hifi.colors.lightGray
}
}
}
}

View file

@ -1,14 +1,28 @@
//
// ModalWindow.qml
//
// Created by Bradley Austin Davis on 22 Jan 2016
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import "."
Window {
id: root
anchors.centerIn: parent
id: window
modality: Qt.ApplicationModal
destroyOnCloseButton: true
destroyOnInvisible: true
frame: ModalFrame{}
destroyOnHidden: true
frame: ModalFrame { }
property int colorScheme: hifi.colorSchemes.light
property bool draggable: false
signal frameClicked();
anchors.centerIn: draggable ? undefined : parent
}

View file

@ -1,9 +1,20 @@
//
// Window.qml
//
// Created by Bradley Austin Davis on 12 Jan 2016
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtGraphicalEffects 1.0
import "."
import "../styles"
import "../styles-uit"
// FIXME how do I set the initial position of a window without
// overriding places where the a individual client of the window
@ -15,16 +26,36 @@ import "../styles"
Fadable {
id: window
HifiConstants { id: hifi }
//
// Signals
//
signal windowDestroyed();
//
// Native properties
//
// The Window size is the size of the content, while the frame
// decorations can extend outside it.
implicitHeight: content ? content.height : 0
implicitWidth: content ? content.width : 0
x: desktop.invalid_position; y: desktop.invalid_position;
enabled: visible
children: [ swallower, frame, pane, activator ]
signal windowDestroyed();
//
// Custom properties
//
property int modality: Qt.NonModal
// Corresponds to the window shown / hidden state AS DISTINCT from window visibility.
// Window visibility should NOT be used as a proxy for any other behavior.
property bool shown: true
// FIXME workaround to deal with the face that some visual items are defined here,
// when they should be moved to a frame derived type
property bool hideBackground: false
visible: shown
enabled: visible
readonly property bool topLevelWindow: true
property string title
// Should the window be closable control?
@ -34,17 +65,23 @@ Fadable {
// 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 destroyOnHidden: false
property bool pinnable: true
property bool pinned: false
property bool resizable: false
property bool gradientsSupported: desktop.gradientsSupported
property int colorScheme: hifi.colorSchemes.dark
property vector2d minSize: Qt.vector2d(100, 100)
property vector2d maxSize: Qt.vector2d(1280, 720)
property vector2d maxSize: Qt.vector2d(1280, 800)
// The content to place inside the window, determined by the client
default property var content
property var footer: Item { } // Optional static footer at the bottom of the dialog.
function setDefaultFocus() {} // Default function; can be overridden by dialogs.
property var rectifier: Timer {
property bool executing: false;
interval: 100
@ -65,20 +102,15 @@ Fadable {
}
}
onXChanged: rectifier.begin();
onYChanged: rectifier.begin();
// 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
x: frame.decoration.anchors.leftMargin
y: frame.decoration.anchors.topMargin
propagateComposedEvents: true
hoverEnabled: true
acceptedButtons: Qt.AllButtons
enabled: window.visible
onPressed: {
@ -94,7 +126,7 @@ Fadable {
property var swallower: MouseArea {
width: frame.decoration.width
height: frame.decoration.height
x: frame.decoration.anchors.margins
x: frame.decoration.anchors.leftMargin
y: frame.decoration.anchors.topMargin
hoverEnabled: true
acceptedButtons: Qt.AllButtons
@ -106,24 +138,217 @@ Fadable {
onWheel: {}
}
// 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 { }
// Scrollable window content.
// FIXME this should not define any visual content in this type. The base window
// type should only consist of logic sized areas, with nothing drawn (although the
// default value for the frame property does include visual decorations)
property var pane: Item {
property bool isScrolling: scrollView.height < scrollView.contentItem.height
property int contentWidth: scrollView.width - (isScrolling ? 10 : 0)
property int scrollHeight: scrollView.height
children: [ swallower, frame, content, activator ]
anchors.fill: parent
anchors.rightMargin: isScrolling ? 11 : 0
Rectangle {
id: contentBackground
anchors.fill: parent
anchors.rightMargin: parent.isScrolling ? 11 : 0
color: hifi.colors.baseGray
visible: !window.hideBackground && modality != Qt.ApplicationModal
}
LinearGradient {
visible: !window.hideBackground && gradientsSupported && modality != Qt.ApplicationModal
anchors.top: contentBackground.bottom
anchors.left: contentBackground.left
width: contentBackground.width - 1
height: 4
start: Qt.point(0, 0)
end: Qt.point(0, 4)
gradient: Gradient {
GradientStop { position: 0.0; color: hifi.colors.darkGray }
GradientStop { position: 1.0; color: hifi.colors.darkGray0 }
}
cached: true
}
ScrollView {
id: scrollView
contentItem: content
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
verticalScrollBarPolicy: Qt.ScrollBarAsNeeded
anchors.fill: parent
anchors.rightMargin: parent.isScrolling ? 1 : 0
anchors.bottomMargin: footer.height > 0 ? footerPane.height : 0
style: ScrollViewStyle {
padding.right: -7 // Move to right away from content.
handle: Item {
implicitWidth: 8
Rectangle {
radius: 4
color: hifi.colors.white30
anchors {
fill: parent
leftMargin: 2 // Finesse size and position.
topMargin: 1
bottomMargin: 1
}
}
}
scrollBarBackground: Item {
implicitWidth: 10
Rectangle {
color: hifi.colors.darkGray30
radius: 4
anchors {
fill: parent
topMargin: -1 // Finesse size
bottomMargin: -2
}
}
}
incrementControl: Item {
visible: false
}
decrementControl: Item {
visible: false
}
}
}
Rectangle {
// Optional non-scrolling footer.
id: footerPane
anchors {
left: parent.left
bottom: parent.bottom
}
width: parent.contentWidth
height: footer.height + 2 * hifi.dimensions.contentSpacing.y + 3
color: hifi.colors.baseGray
visible: footer.height > 0
Item {
// Horizontal rule.
anchors.fill: parent
Rectangle {
width: parent.width
height: 1
y: 1 // Stop displaying content just above horizontal rule/=.
color: hifi.colors.baseGrayShadow
}
Rectangle {
width: parent.width
height: 1
y: 2
color: hifi.colors.baseGrayHighlight
}
}
Item {
anchors.fill: parent
anchors.topMargin: 3 // Horizontal rule.
children: [ footer ]
}
}
}
//
// Handlers
//
Component.onCompleted: {
window.parentChanged.connect(raise);
raise();
centerOrReposition();
setDefaultFocus();
d.centerOrReposition();
d.updateVisibility(shown);
}
Component.onDestruction: {
window.parentChanged.disconnect(raise); // Prevent warning on shutdown
windowDestroyed();
}
onXChanged: rectifier.begin();
onYChanged: rectifier.begin();
onShownChanged: d.updateVisibility(shown)
onVisibleChanged: {
enabled = visible
if (visible && parent) {
d.centerOrReposition();
}
}
QtObject {
id: d
readonly property alias pinned: window.pinned
readonly property alias shown: window.shown
readonly property alias modality: window.modality;
function getTargetVisibility() {
if (!window.shown) {
return false;
}
if (modality !== Qt.NonModal) {
return true;
}
if (pinned) {
return true;
}
if (desktop && !desktop.pinned) {
return true;
}
return false;
}
// The force flag causes all windows to fade back in, because a window was shown
readonly property alias visible: window.visible
function updateVisibility(force) {
if (force && !pinned && desktop.pinned) {
// Change the pinned state (which in turn will call us again)
desktop.pinned = false;
return;
}
var targetVisibility = getTargetVisibility();
if (targetVisibility === visible) {
return;
}
if (targetVisibility) {
fadeIn(function() {
if (force) {
window.raise();
}
});
} else {
fadeOut(function() {
if (!window.shown && window.destroyOnHidden) {
window.destroy();
}
});
}
}
function centerOrReposition() {
if (x == desktop.invalid_position && y == desktop.invalid_position) {
desktop.centerOnVisible(window);
@ -132,20 +357,11 @@ Fadable {
}
}
onVisibleChanged: {
if (!visible && destroyOnInvisible) {
destroy();
return;
}
if (visible) {
raise();
}
enabled = visible
if (visible && parent) {
centerOrReposition();
}
}
// When the desktop pinned state changes, automatically handle the current windows
Connections { target: desktop; onPinnedChanged: d.updateVisibility() }
function raise() {
if (visible && parent) {
@ -153,24 +369,10 @@ Fadable {
}
}
function pin() {
// pinned = ! pinned
function setPinned() {
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
// FIXME using this close function messes up the visibility signals received by the
// type and it's derived types
// function close() {
// console.log("Closing " + window)
// if (destroyOnCloseButton) {
// destroyOnInvisible = true
// }
// visible = false;
// }
function framedRect() {
if (!frame || !frame.decoration) {
return Qt.rect(0, 0, window.width, window.height)
@ -180,7 +382,6 @@ Fadable {
window.height - frame.decoration.anchors.topMargin - frame.decoration.anchors.bottomMargin)
}
Keys.onPressed: {
switch(event.key) {
case Qt.Key_Control:
@ -189,10 +390,9 @@ Fadable {
case Qt.Key_Alt:
break;
case Qt.Key_W:
if (window.closable && (event.modifiers === Qt.ControlModifier)) {
visible = false
shown = false
event.accepted = true
}
// fall through

View file

@ -2057,7 +2057,8 @@ void Application::keyPressEvent(QKeyEvent* event) {
case Qt::Key_X:
if (isShifted && isMeta) {
auto offscreenUi = DependencyManager::get<OffscreenUi>();
offscreenUi->getRootContext()->engine()->clearComponentCache();
offscreenUi->togglePinned();
//offscreenUi->getRootContext()->engine()->clearComponentCache();
//OffscreenUi::information("Debugging", "Component cache cleared");
// placeholder for dialogs being converted to QML.
}

View file

@ -96,7 +96,7 @@ void OverlayConductor::updateMode() {
myAvatar->reset(true, false, false);
}
if (_wantsOverlays) {
setEnabled(!nowDriving, false);
setEnabled(!nowDriving);
}
_driving = nowDriving;
} // Else haven't accumulated enough time in new mode, but keep timing.
@ -114,18 +114,14 @@ void OverlayConductor::updateMode() {
case SITTING: {
// enter the SITTING state
// place the overlay at origin
Transform identity;
qApp->getApplicationCompositor().setModelTransform(identity);
qApp->getApplicationCompositor().setModelTransform(Transform());
break;
}
case STANDING: { // STANDING mode is not currently used.
// enter the STANDING state
// place the overlay at the current hmd position in world space
auto camMat = cancelOutRollAndPitch(myAvatar->getSensorToWorldMatrix() * qApp->getHMDSensorPose());
Transform t;
t.setTranslation(extractTranslation(camMat));
t.setRotation(glm::quat_cast(camMat));
qApp->getApplicationCompositor().setModelTransform(t);
qApp->getApplicationCompositor().setModelTransform(Transform(camMat));
break;
}
@ -139,53 +135,20 @@ void OverlayConductor::updateMode() {
}
void OverlayConductor::setEnabled(bool enabled, bool toggleQmlEvents) {
void OverlayConductor::setEnabled(bool enabled) {
if (enabled == _enabled) {
return;
}
if (toggleQmlEvents) { // Could recurse on us with the wrong toggleQmlEvents flag, and not need in the !toggleQmlEvent case anyway.
Menu::getInstance()->setIsOptionChecked(MenuOption::Overlays, enabled);
}
_enabled = enabled; // set the new value
// if the new state is visible/enabled...
if (_enabled) {
// alpha fadeIn the overlay mesh.
qApp->getApplicationCompositor().fadeIn();
// enable mouse clicks from script
qApp->getOverlays().enable();
// enable QML events
if (toggleQmlEvents) {
auto offscreenUi = DependencyManager::get<OffscreenUi>();
offscreenUi->getRootItem()->setEnabled(true);
}
if (_mode == STANDING) {
offscreenUi->setPinned(!_enabled);
// if the new state is visible/enabled...
if (_enabled && _mode == STANDING) {
// place the overlay at the current hmd position in world space
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
auto camMat = cancelOutRollAndPitch(myAvatar->getSensorToWorldMatrix() * qApp->getHMDSensorPose());
Transform t;
t.setTranslation(extractTranslation(camMat));
t.setRotation(glm::quat_cast(camMat));
qApp->getApplicationCompositor().setModelTransform(t);
}
} else { // other wise, if the new state is hidden/not enabled
// alpha fadeOut the overlay mesh.
qApp->getApplicationCompositor().fadeOut();
// disable mouse clicks from script
qApp->getOverlays().disable();
// disable QML events
if (toggleQmlEvents) { // I'd really rather always do this, but it looses drive state. bugzid:501
auto offscreenUi = DependencyManager::get<OffscreenUi>();
offscreenUi->getRootItem()->setEnabled(false);
}
qApp->getApplicationCompositor().setModelTransform(Transform(camMat));
}
}

View file

@ -17,7 +17,7 @@ public:
~OverlayConductor();
void update(float dt);
void setEnabled(bool enable, bool toggleQmlEvents = true);
void setEnabled(bool enable);
bool getEnabled() const;
private:

View file

@ -346,7 +346,7 @@ bool CompositorHelper::calculateRayUICollisionPoint(const glm::vec3& position, c
auto relativePosition = vec3(relativePosition4) / relativePosition4.w;
auto relativeDirection = glm::inverse(glm::quat_cast(UITransform)) * direction;
float uiRadius = _oculusUIRadius; // * myAvatar->getUniformScale(); // FIXME - how do we want to handle avatar scale
float uiRadius = _hmdUIRadius; // * myAvatar->getUniformScale(); // FIXME - how do we want to handle avatar scale
float instersectionDistance;
if (raySphereIntersect(relativeDirection, relativePosition, uiRadius, &instersectionDistance)){
@ -407,60 +407,6 @@ void CompositorHelper::updateTooltips() {
//}
}
static const float FADE_DURATION = 500.0f;
static const float FADE_IN_ALPHA = 1.0f;
static const float FADE_OUT_ALPHA = 0.0f;
void CompositorHelper::startFadeFailsafe(float endValue) {
_fadeStarted = usecTimestampNow();
_fadeFailsafeEndValue = endValue;
const int SLIGHT_DELAY = 10;
QTimer::singleShot(FADE_DURATION + SLIGHT_DELAY, [this]{
checkFadeFailsafe();
});
}
void CompositorHelper::checkFadeFailsafe() {
auto elapsedInFade = usecTimestampNow() - _fadeStarted;
if (elapsedInFade > FADE_DURATION) {
setAlpha(_fadeFailsafeEndValue);
}
}
void CompositorHelper::fadeIn() {
_fadeInAlpha = true;
_alphaPropertyAnimation->setDuration(FADE_DURATION);
_alphaPropertyAnimation->setStartValue(_alpha);
_alphaPropertyAnimation->setEndValue(FADE_IN_ALPHA);
_alphaPropertyAnimation->start();
// Sometimes, this "QPropertyAnimation" fails to complete the animation, and we end up with a partially faded
// state. So we will also have this fail-safe, where we record the timestamp of the fadeRequest, and the target
// value of the fade, and if after that time we still haven't faded all the way, we will kick it to the final
// fade value
startFadeFailsafe(FADE_IN_ALPHA);
}
void CompositorHelper::fadeOut() {
_fadeInAlpha = false;
_alphaPropertyAnimation->setDuration(FADE_DURATION);
_alphaPropertyAnimation->setStartValue(_alpha);
_alphaPropertyAnimation->setEndValue(FADE_OUT_ALPHA);
_alphaPropertyAnimation->start();
startFadeFailsafe(FADE_OUT_ALPHA);
}
void CompositorHelper::toggle() {
if (_fadeInAlpha) {
fadeOut();
} else {
fadeIn();
}
}
glm::mat4 CompositorHelper::getReticleTransform(const glm::mat4& eyePose, const glm::vec3& headPosition) const {
glm::mat4 result;
if (isHMD()) {

View file

@ -38,7 +38,6 @@ const float MAGNIFY_MULT = 2.0f;
class CompositorHelper : public QObject, public Dependency {
Q_OBJECT
Q_PROPERTY(float alpha READ getAlpha WRITE setAlpha)
Q_PROPERTY(bool reticleOverDesktop READ getReticleOverDesktop WRITE setReticleOverDesktop)
public:
static const uvec2 VIRTUAL_SCREEN_SIZE;
@ -75,13 +74,6 @@ public:
void setModelTransform(const Transform& transform) { _modelTransform = transform; }
const Transform& getModelTransform() const { return _modelTransform; }
void fadeIn();
void fadeOut();
void toggle();
float getAlpha() const { return _alpha; }
void setAlpha(float alpha) { _alpha = alpha; }
bool getReticleVisible() const { return _reticleVisible; }
void setReticleVisible(bool visible) { _reticleVisible = visible; }
@ -113,7 +105,7 @@ public:
void setReticleOverDesktop(bool value) { _isOverDesktop = value; }
void setDisplayPlugin(const DisplayPluginPointer& displayPlugin) { _currentDisplayPlugin = displayPlugin; }
void setFrameInfo(uint32_t frame, const glm::mat4& camera) { _currentCamera = camera; _currentFrame = frame; }
void setFrameInfo(uint32_t frame, const glm::mat4& camera) { _currentCamera = camera; }
signals:
void allowMouseCaptureChanged();
@ -127,7 +119,6 @@ private:
DisplayPluginPointer _currentDisplayPlugin;
glm::mat4 _currentCamera;
uint32_t _currentFrame { 0 };
QWidget* _renderingWidget{ nullptr };
//// Support for hovering and tooltips
@ -143,17 +134,7 @@ private:
float _textureFov { VIRTUAL_UI_TARGET_FOV.y };
float _textureAspectRatio { VIRTUAL_UI_ASPECT_RATIO };
float _alpha { 1.0f };
float _prevAlpha { 1.0f };
float _fadeInAlpha { true };
float _oculusUIRadius { 1.0f };
quint64 _fadeStarted { 0 };
float _fadeFailsafeEndValue { 1.0f };
void checkFadeFailsafe();
void startFadeFailsafe(float endValue);
int _reticleQuad;
float _hmdUIRadius { 1.0f };
int _previousBorderWidth { -1 };
int _previousBorderHeight { -1 };

View file

@ -445,11 +445,6 @@ void OpenGLDisplayPlugin::compositeOverlay() {
useProgram(_program);
// check the alpha
auto overlayAlpha = compositorHelper->getAlpha();
if (overlayAlpha > 0.0f) {
// set the alpha
Uniform<float>(*_program, _alphaUniform).Set(overlayAlpha);
// Overlay draw
if (isStereo()) {
Uniform<glm::mat4>(*_program, _mvpUniform).Set(mat4());
@ -462,8 +457,6 @@ void OpenGLDisplayPlugin::compositeOverlay() {
Uniform<glm::mat4>(*_program, _mvpUniform).Set(mat4());
drawUnitQuad();
}
}
Uniform<float>(*_program, _alphaUniform).Set(1.0);
}
void OpenGLDisplayPlugin::compositePointer() {
@ -471,12 +464,6 @@ void OpenGLDisplayPlugin::compositePointer() {
auto compositorHelper = DependencyManager::get<CompositorHelper>();
useProgram(_program);
// check the alpha
auto overlayAlpha = compositorHelper->getAlpha();
if (overlayAlpha > 0.0f) {
// set the alpha
Uniform<float>(*_program, _alphaUniform).Set(overlayAlpha);
Uniform<glm::mat4>(*_program, _mvpUniform).Set(compositorHelper->getReticleTransform(glm::mat4()));
if (isStereo()) {
for_each_eye([&](Eye eye) {
@ -486,9 +473,7 @@ void OpenGLDisplayPlugin::compositePointer() {
} else {
drawUnitQuad();
}
}
Uniform<glm::mat4>(*_program, _mvpUniform).Set(mat4());
Uniform<float>(*_program, _alphaUniform).Set(1.0);
}
void OpenGLDisplayPlugin::compositeScene() {

View file

@ -254,13 +254,7 @@ void HmdDisplayPlugin::compositeOverlay() {
using namespace oglplus;
auto compositorHelper = DependencyManager::get<CompositorHelper>();
// check the alpha
useProgram(_program);
auto overlayAlpha = compositorHelper->getAlpha();
if (overlayAlpha > 0.0f) {
// set the alpha
Uniform<float>(*_program, _alphaUniform).Set(overlayAlpha);
_sphereSection->Use();
for_each_eye([&](Eye eye) {
eyeViewport(eye);
@ -269,8 +263,6 @@ void HmdDisplayPlugin::compositeOverlay() {
Uniform<glm::mat4>(*_program, _mvpUniform).Set(mvp);
_sphereSection->Draw();
});
}
Uniform<float>(*_program, _alphaUniform).Set(1.0);
}
void HmdDisplayPlugin::compositePointer() {
@ -280,10 +272,6 @@ void HmdDisplayPlugin::compositePointer() {
// check the alpha
useProgram(_program);
auto overlayAlpha = compositorHelper->getAlpha();
if (overlayAlpha > 0.0f) {
// set the alpha
Uniform<float>(*_program, _alphaUniform).Set(overlayAlpha);
// Mouse pointer
_plane->Use();
@ -297,8 +285,6 @@ void HmdDisplayPlugin::compositePointer() {
Uniform<glm::mat4>(*_program, _mvpUniform).Set(mvp);
_plane->Draw();
});
}
Uniform<float>(*_program, _alphaUniform).Set(1.0);
}
void HmdDisplayPlugin::internalPresent() {

View file

@ -22,10 +22,6 @@ QString ErrorDialog::text() const {
return _text;
}
void ErrorDialog::setVisible(bool v) {
OffscreenQmlDialog::setVisible(v);
}
void ErrorDialog::setText(const QString& arg) {
if (arg != _text) {
_text = arg;

View file

@ -30,7 +30,6 @@ public:
QString text() const;
public slots:
virtual void setVisible(bool v);
void setText(const QString& arg);
signals:

View file

@ -17,7 +17,7 @@ OffscreenQmlDialog::~OffscreenQmlDialog() {
}
void OffscreenQmlDialog::hide() {
static_cast<QQuickItem*>(parent())->setVisible(false);
parent()->setProperty(OFFSCREEN_VISIBILITY_PROPERTY, false);
}
QString OffscreenQmlDialog::title() const {

View file

@ -121,32 +121,28 @@ void OffscreenUi::show(const QUrl& url, const QString& name, std::function<void(
load(url, f);
item = getRootItem()->findChild<QQuickItem*>(name);
}
if (item) {
item->setVisible(true);
QQmlProperty(item, OFFSCREEN_VISIBILITY_PROPERTY).write(true);
}
}
void OffscreenUi::toggle(const QUrl& url, const QString& name, std::function<void(QQmlContext*, QObject*)> f) {
QQuickItem* item = getRootItem()->findChild<QQuickItem*>(name);
// Already loaded?
if (item) {
emit showDesktop();
item->setVisible(!item->isVisible());
if (!item) {
show(url, name, f);
return;
}
load(url, f);
item = getRootItem()->findChild<QQuickItem*>(name);
if (item && !item->isVisible()) {
emit showDesktop();
item->setVisible(true);
}
// Already loaded, so just flip the bit
QQmlProperty shownProperty(item, OFFSCREEN_VISIBILITY_PROPERTY);
shownProperty.write(!shownProperty.read().toBool());
}
void OffscreenUi::hide(const QString& name) {
QQuickItem* item = getRootItem()->findChild<QQuickItem*>(name);
if (item) {
item->setVisible(false);
QQmlProperty(item, OFFSCREEN_VISIBILITY_PROPERTY).write(false);
}
}
@ -345,6 +341,20 @@ QVariant OffscreenUi::inputDialog(const Icon icon, const QString& title, const Q
return waitForInputDialogResult(createInputDialog(icon, title, label, current));
}
void OffscreenUi::togglePinned() {
bool invokeResult = QMetaObject::invokeMethod(_desktop, "togglePinned");
if (!invokeResult) {
qWarning() << "Failed to toggle window visibility";
}
}
void OffscreenUi::setPinned(bool pinned) {
bool invokeResult = QMetaObject::invokeMethod(_desktop, "setPinned", Q_ARG(QVariant, pinned));
if (!invokeResult) {
qWarning() << "Failed to set window visibility";
}
}
void OffscreenUi::addMenuInitializer(std::function<void(VrMenu*)> f) {
if (!_vrMenu) {
_queuedMenuInitializers.push_back(f);

View file

@ -28,6 +28,8 @@
class VrMenu;
#define OFFSCREEN_VISIBILITY_PROPERTY "shown"
class OffscreenUi : public OffscreenQmlSurface, public Dependency {
Q_OBJECT
@ -44,6 +46,13 @@ public:
void setNavigationFocused(bool focused);
void unfocusWindows();
void toggleMenu(const QPoint& screenCoordinates);
// Setting pinned to true will hide all overlay elements on the desktop that don't have a pinned flag
void setPinned(bool pinned = true);
void togglePinned();
bool eventFilter(QObject* originalDestination, QEvent* event) override;
void addMenuInitializer(std::function<void(VrMenu*)> f);

View file

@ -163,8 +163,7 @@ void QmlWindowClass::setVisible(bool visible) {
QMetaObject::invokeMethod(targetWindow, "showTabForUrl", Qt::QueuedConnection, Q_ARG(QVariant, _source), Q_ARG(QVariant, visible));
} else {
DependencyManager::get<OffscreenUi>()->executeOnUiThread([=] {
targetWindow->setVisible(visible);
//emit visibilityChanged(visible);
targetWindow->setProperty(OFFSCREEN_VISIBILITY_PROPERTY, visible);
});
}
}

View file

@ -47,10 +47,6 @@ void Tooltip::setImageURL(const QString& imageURL) {
}
}
void Tooltip::setVisible(bool visible) {
QQuickItem::setVisible(visible);
}
QString Tooltip::showTip(const QString& title, const QString& description) {
const QString newTipId = QUuid().createUuid().toString();

View file

@ -39,8 +39,6 @@ public:
static void closeTip(const QString& tipId);
public slots:
virtual void setVisible(bool v);
void setTitle(const QString& title);
void setDescription(const QString& description);
void setImageURL(const QString& imageURL);

View file

@ -256,7 +256,7 @@ ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPosit
y: y - ToolBar.SPACING
});
}
this.save();
//this.save();
}
this.setAlpha = function(alpha, tool) {

View file

@ -5,7 +5,7 @@ import Qt.labs.settings 1.0
import "../../../interface/resources/qml"
//import "../../../interface/resources/qml/windows"
import "../../../interface/resources/qml/windows-uit"
import "../../../interface/resources/qml/windows"
import "../../../interface/resources/qml/dialogs"
import "../../../interface/resources/qml/hifi"
import "../../../interface/resources/qml/hifi/dialogs"
@ -17,25 +17,7 @@ ApplicationWindow {
width: 1280
height: 800
title: qsTr("Scratch App")
HifiConstants { id: hifi }
Desktop {
id: desktop
anchors.fill: parent
//rootMenu: StubMenu { id: rootMenu }
//Component.onCompleted: offscreenWindow = appWindow
/*
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.RightButton
onClicked: desktop.popupMenu(Qt.vector2d(mouseX, mouseY));
}
*/
Row {
toolBar: Row {
id: testButtons
anchors { margins: 8; left: parent.left; top: parent.top }
spacing: 8
@ -44,51 +26,20 @@ ApplicationWindow {
property var tabs: [];
property var urls: [];
Button {
// Shows the dialog with preferences sections but not each section's preference items
// because Preferences.preferencesByCategory() method is not stubbed out.
text: "Settings > General..."
property var builder: Component {
GeneralPreferencesDialog { }
}
onClicked: {
var runningScripts = builder.createObject(desktop);
}
}
// Window visibility
Button {
text: "Running Scripts"
property var builder: Component {
RunningScripts { }
}
onClicked: {
var runningScripts = builder.createObject(desktop);
}
}
Button {
text: "Attachments"
property var builder: Component {
AttachmentsDialog { }
}
onClicked: {
var attachmentsDialog = builder.createObject(desktop);
}
}
/*
Button {
text: "restore all"
onClicked: {
for (var i = 0; i < desktop.windows.length; ++i) {
desktop.windows[i].visible = true
desktop.windows[i].shown = true
}
}
}
Button {
text: "toggle blue visible"
onClicked: {
blue.visible = !blue.visible
blue.shown = !blue.shown
}
}
Button {
@ -97,27 +48,14 @@ ApplicationWindow {
blue.enabled = !blue.enabled
}
}
*/
Button {
// Replicates message box that pops up after selecting new avatar. Includes title.
text: "Confirm Avatar"
onClicked: {
var messageBox = desktop.messageBox({
title: "Set Avatar",
text: "Would you like to use 'Albert' for your avatar?",
icon: hifi.icons.question, // Test question icon
//icon: hifi.icons.information, // Test informaton icon
//icon: hifi.icons.warning, // Test warning icon
//icon: hifi.icons.critical, // Test critical icon
//icon: hifi.icons.none, // Test no icon
buttons: OriginalDialogs.StandardButton.Ok + OriginalDialogs.StandardButton.Cancel,
defaultButton: OriginalDialogs.StandardButton.Ok
});
messageBox.selected.connect(function(button) {
console.log("You clicked " + button)
})
}
text: "toggle desktop"
onClicked: desktop.toggleVisible()
}
// Error alerts
/*
Button {
// Message without title.
text: "Show Error"
@ -143,40 +81,9 @@ ApplicationWindow {
});
}
}
Button {
text: "Bookmark Location"
onClicked: {
desktop.inputDialog({
title: "Bookmark Location",
icon: hifi.icons.placemark,
label: "Name"
});
}
}
Button {
text: "Delete Bookmark"
onClicked: {
desktop.inputDialog({
title: "Delete Bookmark",
icon: hifi.icons.placemark,
label: "Select the bookmark to delete",
items: ["Bookmark A", "Bookmark B", "Bookmark C"]
});
}
}
Button {
text: "Duplicate Bookmark"
onClicked: {
desktop.messageBox({
title: "Duplicate Bookmark",
icon: hifi.icons.warning,
text: "The bookmark name you entered alread exists in yoru list.",
informativeText: "Would you like to overwrite it?",
buttons: OriginalDialogs.StandardButton.Yes + OriginalDialogs.StandardButton.No,
defaultButton: OriginalDialogs.StandardButton.Yes
});
}
}
*/
// query
/*
// There is no such desktop.queryBox() function; may need to update test to cover QueryDialog.qml?
Button {
@ -197,6 +104,19 @@ ApplicationWindow {
}
}
*/
// Browser
Button {
text: "Open Browser"
onClicked: builder.createObject(desktop);
property var builder: Component {
Browser {}
}
}
// file dialog
Button {
text: "Open Directory"
property var builder: Component {
@ -213,7 +133,6 @@ ApplicationWindow {
})
}
}
Button {
text: "Open File"
property var builder: Component {
@ -234,7 +153,11 @@ ApplicationWindow {
})
}
}
/*
*/
// tabs
/*
Button {
text: "Add Tab"
onClicked: {
@ -269,15 +192,126 @@ ApplicationWindow {
desktop.toolWindow.removeTabForUrl("Foo");
}
}
*/
// Hifi specific stuff
/*
Button {
// Shows the dialog with preferences sections but not each section's preference items
// because Preferences.preferencesByCategory() method is not stubbed out.
text: "Settings > General..."
property var builder: Component {
GeneralPreferencesDialog { }
}
onClicked: {
var runningScripts = builder.createObject(desktop);
}
}
Button {
text: "Running Scripts"
property var builder: Component {
RunningScripts { }
}
onClicked: {
var runningScripts = builder.createObject(desktop);
}
}
Button {
text: "Attachments"
property var builder: Component {
AttachmentsDialog { }
}
onClicked: {
var attachmentsDialog = builder.createObject(desktop);
}
}
Button {
// Replicates message box that pops up after selecting new avatar. Includes title.
text: "Confirm Avatar"
onClicked: {
var messageBox = desktop.messageBox({
title: "Set Avatar",
text: "Would you like to use 'Albert' for your avatar?",
icon: hifi.icons.question, // Test question icon
//icon: hifi.icons.information, // Test informaton icon
//icon: hifi.icons.warning, // Test warning icon
//icon: hifi.icons.critical, // Test critical icon
//icon: hifi.icons.none, // Test no icon
buttons: OriginalDialogs.StandardButton.Ok + OriginalDialogs.StandardButton.Cancel,
defaultButton: OriginalDialogs.StandardButton.Ok
});
messageBox.selected.connect(function(button) {
console.log("You clicked " + button)
})
}
}
*/
// bookmarks
/*
Button {
text: "Bookmark Location"
onClicked: {
desktop.inputDialog({
title: "Bookmark Location",
icon: hifi.icons.placemark,
label: "Name"
});
}
}
Button {
text: "Delete Bookmark"
onClicked: {
desktop.inputDialog({
title: "Delete Bookmark",
icon: hifi.icons.placemark,
label: "Select the bookmark to delete",
items: ["Bookmark A", "Bookmark B", "Bookmark C"]
});
}
}
Button {
text: "Duplicate Bookmark"
onClicked: {
desktop.messageBox({
title: "Duplicate Bookmark",
icon: hifi.icons.warning,
text: "The bookmark name you entered alread exists in yoru list.",
informativeText: "Would you like to overwrite it?",
buttons: OriginalDialogs.StandardButton.Yes + OriginalDialogs.StandardButton.No,
defaultButton: OriginalDialogs.StandardButton.Yes
});
}
}
*/
}
HifiConstants { id: hifi }
Desktop {
id: desktop
anchors.fill: parent
//rootMenu: StubMenu { id: rootMenu }
//Component.onCompleted: offscreenWindow = appWindow
/*
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.RightButton
onClicked: desktop.popupMenu(Qt.vector2d(mouseX, mouseY));
}
*/
Window {
id: blue
closable: true
visible: true
resizable: true
destroyOnInvisible: false
destroyOnHidden: false
width: 100; height: 100
x: 1280 / 2; y: 720 / 2
@ -296,32 +330,33 @@ ApplicationWindow {
Component.onDestruction: console.log("Blue destroyed")
}
}
*/
/*
Rectangle { width: 100; height: 100; x: 100; y: 100; color: "#00f" }
Window {
id: green
alwaysOnTop: true
frame: HiddenFrame{}
hideBackground: true
closable: true
visible: true
resizable: false
x: 1280 / 2; y: 720 / 2
Settings {
category: "TestWindow.Green"
property alias x: green.x
property alias y: green.y
property alias width: green.width
property alias height: green.height
}
width: 100; height: 100
Rectangle { anchors.fill: parent; color: "green" }
Rectangle {
color: "#0f0"
width: green.width;
height: green.height;
}
}
/*
Window {
id: yellow
objectName: "Yellow"
closable: true
visible: true
resizable: true
x: 100; y: 100
width: 100; height: 100
Rectangle {
anchors.fill: parent
@ -329,10 +364,11 @@ ApplicationWindow {
color: "yellow"
}
}
*/
*/
}
Action {
id: openBrowserAction
text: "Open Browser"
shortcut: "Ctrl+Shift+X"
onTriggered: {

View file

@ -18,6 +18,7 @@ DISTFILES += \
qml/*.qml \
../../interface/resources/qml/*.qml \
../../interface/resources/qml/controls/*.qml \
../../interface/resources/qml/controls-uit/*.qml \
../../interface/resources/qml/dialogs/*.qml \
../../interface/resources/qml/dialogs/fileDialog/*.qml \
../../interface/resources/qml/dialogs/preferences/*.qml \
@ -25,9 +26,9 @@ DISTFILES += \
../../interface/resources/qml/desktop/*.qml \
../../interface/resources/qml/menus/*.qml \
../../interface/resources/qml/styles/*.qml \
../../interface/resources/qml/styles-uit/*.qml \
../../interface/resources/qml/windows/*.qml \
../../interface/resources/qml/hifi/*.qml \
../../interface/resources/qml/hifi/dialogs/*.qml \
../../interface/resources/qml/hifi/dialogs/preferences/*.qml \
../../interface/resources/qml/hifi/overlays/*.qml