Merge pull request #13591 from Cristo86/android_revert_pr12888_qmls

Rollback PR 12888 by deleting alternative +android files
This commit is contained in:
Sam Gondelman 2018-07-12 12:06:35 -07:00 committed by GitHub
commit 2597568a0a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 0 additions and 2807 deletions

View file

@ -1,125 +0,0 @@
//
// Button.qml
//
// Created by David Rowe on 16 Feb 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 as Original
import QtQuick.Controls.Styles 1.4
import TabletScriptingInterface 1.0
import "../styles-uit"
Original.Button {
id: root;
property int color: 0
property int colorScheme: hifi.colorSchemes.light
property string buttonGlyph: "";
width: hifi.dimensions.buttonWidth
height: hifi.dimensions.controlLineHeight
HifiConstants { id: hifi }
onHoveredChanged: {
if (hovered) {
Tablet.playSound(TabletEnums.ButtonHover);
}
}
onFocusChanged: {
if (focus) {
Tablet.playSound(TabletEnums.ButtonHover);
}
}
onClicked: {
Tablet.playSound(TabletEnums.ButtonClick);
}
style: ButtonStyle {
background: Rectangle {
radius: hifi.buttons.radius
border.width: (control.color === hifi.buttons.none ||
(control.color === hifi.buttons.noneBorderless && control.hovered) ||
(control.color === hifi.buttons.noneBorderlessWhite && control.hovered) ||
(control.color === hifi.buttons.noneBorderlessGray && control.hovered)) ? 1 : 0;
border.color: control.color === hifi.buttons.noneBorderless ? hifi.colors.blueHighlight :
(control.color === hifi.buttons.noneBorderlessGray ? hifi.colors.baseGray : hifi.colors.white);
gradient: Gradient {
GradientStop {
position: 0.2
color: {
if (!control.enabled) {
hifi.buttons.disabledColorStart[control.colorScheme]
} else if (control.pressed) {
hifi.buttons.pressedColor[control.color]
} else if (control.hovered) {
hifi.buttons.hoveredColor[control.color]
} else if (!control.hovered && control.focus) {
hifi.buttons.focusedColor[control.color]
} else {
hifi.buttons.colorStart[control.color]
}
}
}
GradientStop {
position: 1.0
color: {
if (!control.enabled) {
hifi.buttons.disabledColorFinish[control.colorScheme]
} else if (control.pressed) {
hifi.buttons.pressedColor[control.color]
} else if (control.hovered) {
hifi.buttons.hoveredColor[control.color]
} else if (!control.hovered && control.focus) {
hifi.buttons.focusedColor[control.color]
} else {
hifi.buttons.colorFinish[control.color]
}
}
}
}
}
label: Item {
HiFiGlyphs {
id: buttonGlyph;
visible: root.buttonGlyph !== "";
text: root.buttonGlyph === "" ? hifi.glyphs.question : root.buttonGlyph;
// Size
size: 34;
// Anchors
anchors.right: buttonText.left;
anchors.top: parent.top;
anchors.bottom: parent.bottom;
// Style
color: enabled ? hifi.buttons.textColor[control.color]
: hifi.buttons.disabledTextColor[control.colorScheme];
// Alignment
horizontalAlignment: Text.AlignHCenter;
verticalAlignment: Text.AlignVCenter;
}
RalewayBold {
id: buttonText;
anchors.centerIn: parent;
font.capitalization: Font.AllUppercase
color: enabled ? hifi.buttons.textColor[control.color]
: hifi.buttons.disabledTextColor[control.colorScheme]
size: hifi.fontSizes.buttonLabel
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: control.text
}
}
}
}

View file

@ -1,165 +0,0 @@
//
// Table.qml
//
// Created by David Rowe on 18 Feb 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 QtQuick.Controls 2.2 as QQC2
import "../styles-uit"
TableView {
id: tableView
property int colorScheme: hifi.colorSchemes.light
readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light
property bool expandSelectedRow: false
property bool centerHeaderText: false
readonly property real headerSpacing: 3 //spacing between sort indicator and table header title
property var titlePaintedPos: [] // storing extra data position behind painted
// title text and sort indicatorin table's header
signal titlePaintedPosSignal(int column) //signal that extradata position gets changed
model: ListModel { }
Component.onCompleted: {
if (flickableItem !== null && flickableItem !== undefined) {
tableView.flickableItem.QQC2.ScrollBar.vertical = scrollbar
}
}
QQC2.ScrollBar {
id: scrollbar
parent: tableView.flickableItem
policy: QQC2.ScrollBar.AsNeeded
orientation: Qt.Vertical
visible: size < 1.0
topPadding: tableView.headerVisible ? hifi.dimensions.tableHeaderHeight + 1 : 1
anchors.top: tableView.top
anchors.left: tableView.right
anchors.bottom: tableView.bottom
background: Item {
implicitWidth: hifi.dimensions.scrollbarBackgroundWidth
Rectangle {
anchors {
fill: parent;
topMargin: tableView.headerVisible ? hifi.dimensions.tableHeaderHeight : 0
}
color: isLightColorScheme ? hifi.colors.tableScrollBackgroundLight
: hifi.colors.tableScrollBackgroundDark
}
}
contentItem: Item {
implicitWidth: hifi.dimensions.scrollbarHandleWidth
Rectangle {
anchors.fill: parent
radius: (width - 4)/2
color: isLightColorScheme ? hifi.colors.tableScrollHandleLight : hifi.colors.tableScrollHandleDark
}
}
}
headerVisible: false
headerDelegate: Rectangle {
height: hifi.dimensions.tableHeaderHeight
color: isLightColorScheme ? hifi.colors.tableBackgroundLight : hifi.colors.tableBackgroundDark
RalewayRegular {
id: titleText
x: centerHeaderText ? (parent.width - paintedWidth -
((sortIndicatorVisible &&
sortIndicatorColumn === styleData.column) ?
(titleSort.paintedWidth / 5 + tableView.headerSpacing) : 0)) / 2 :
hifi.dimensions.tablePadding
text: styleData.value
size: hifi.fontSizes.tableHeading
font.capitalization: Font.AllUppercase
color: hifi.colors.baseGrayHighlight
horizontalAlignment: (centerHeaderText ? Text.AlignHCenter : Text.AlignLeft)
anchors.verticalCenter: parent.verticalCenter
}
//actual image of sort indicator in glyph font only 20% of real font size
//i.e. if the charachter size set to 60 pixels, actual image is 12 pixels
HiFiGlyphs {
id: titleSort
text: sortIndicatorOrder == Qt.AscendingOrder ? hifi.glyphs.caratUp : hifi.glyphs.caratDn
color: hifi.colors.darkGray
opacity: 0.6;
size: hifi.fontSizes.tableHeadingIcon
anchors.verticalCenter: titleText.verticalCenter
anchors.left: titleText.right
anchors.leftMargin: -(hifi.fontSizes.tableHeadingIcon / 2.5) + tableView.headerSpacing
visible: sortIndicatorVisible && sortIndicatorColumn === styleData.column
onXChanged: {
titlePaintedPos[styleData.column] = titleText.x + titleText.paintedWidth +
paintedWidth / 5 + tableView.headerSpacing*2
titlePaintedPosSignal(styleData.column)
}
}
Rectangle {
width: 1
anchors {
left: parent.left
top: parent.top
topMargin: 1
bottom: parent.bottom
bottomMargin: 2
}
color: isLightColorScheme ? hifi.colors.lightGrayText : hifi.colors.baseGrayHighlight
visible: styleData.column > 0
}
Rectangle {
height: 1
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
}
color: isLightColorScheme ? hifi.colors.lightGrayText : hifi.colors.baseGrayHighlight
}
}
// Use rectangle to draw border with rounded corners.
frameVisible: false
Rectangle {
color: "#00000000"
anchors { fill: parent; margins: -2 }
border.color: isLightColorScheme ? hifi.colors.lightGrayText : hifi.colors.baseGrayHighlight
border.width: 2
}
anchors.margins: 2 // Shrink TableView to lie within border.
backgroundVisible: true
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
verticalScrollBarPolicy: Qt.ScrollBarAlwaysOff
style: TableViewStyle {
// Needed in order for rows to keep displaying rows after end of table entries.
backgroundColor: tableView.isLightColorScheme ? hifi.colors.tableBackgroundLight : hifi.colors.tableBackgroundDark
alternateBackgroundColor: tableView.isLightColorScheme ? hifi.colors.tableRowLightOdd : hifi.colors.tableRowDarkOdd
padding.top: headerVisible ? hifi.dimensions.tableHeaderHeight: 0
}
rowDelegate: Rectangle {
height: (styleData.selected && expandSelectedRow ? 1.8 : 1) * hifi.dimensions.tableRowHeight
color: styleData.selected
? hifi.colors.primaryHighlight
: tableView.isLightColorScheme
? (styleData.alternate ? hifi.colors.tableRowLightEven : hifi.colors.tableRowLightOdd)
: (styleData.alternate ? hifi.colors.tableRowDarkEven : hifi.colors.tableRowDarkOdd)
}
}

View file

@ -1,575 +0,0 @@
//
// Desktop.qml
//
// Created by Bradley Austin Davis on 15 Apr 2015
// 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.7
import QtQuick.Controls 1.4
import "../dialogs"
import "../js/Utils.js" as Utils
// This is our primary 'desktop' object to which all VR dialogs and windows are childed.
FocusScope {
id: desktop
objectName: "desktop"
anchors.fill: parent
readonly property int invalid_position: -9999;
property rect recommendedRect: Qt.rect(0,0,0,0);
property var expectedChildren;
property bool repositionLocked: true
property bool hmdHandMouseActive: false
onRepositionLockedChanged: {
if (!repositionLocked) {
d.handleSizeChanged();
}
}
onHeightChanged: d.handleSizeChanged();
onWidthChanged: d.handleSizeChanged();
// Controls and windows can trigger this signal to ensure the desktop becomes visible
// when they're opened.
signal showDesktop();
// This is for JS/QML communication, which is unused in the Desktop,
// but not having this here results in spurious warnings about a
// missing signal
signal sendToScript(var message);
// Allows QML/JS to find the desktop through the parent chain
property bool desktopRoot: true
// The VR version of the primary menu
property var rootMenu: Menu {
id: rootMenuId
objectName: "rootMenu"
property var exclusionGroups: ({});
property Component exclusiveGroupMaker: Component {
ExclusiveGroup {
}
}
function addExclusionGroup(qmlAction, exclusionGroup) {
var exclusionGroupId = exclusionGroup.toString();
if(!exclusionGroups[exclusionGroupId]) {
exclusionGroups[exclusionGroupId] = exclusiveGroupMaker.createObject(rootMenuId);
}
qmlAction.exclusiveGroup = exclusionGroups[exclusionGroupId]
}
}
// FIXME: Alpha gradients display as fuschia under QtQuick 2.5 on OSX/AMD
// because shaders are 4.2, and do not include #version declarations.
property bool gradientsSupported: Qt.platform.os != "osx" && !~GL.vendor.indexOf("ATI")
readonly property alias zLevels: zLevels
QtObject {
id: zLevels;
readonly property real normal: 1 // make windows always appear higher than QML overlays and other non-window controls.
readonly property real top: 2000
readonly property real modal: 4000
readonly property real menu: 8000
}
QtObject {
id: d
function handleSizeChanged() {
if (desktop.repositionLocked) {
return;
}
var oldRecommendedRect = recommendedRect;
var newRecommendedRectJS = (typeof Controller === "undefined") ? Qt.rect(0,0,0,0) : Controller.getRecommendedHUDRect();
var newRecommendedRect = Qt.rect(newRecommendedRectJS.x, newRecommendedRectJS.y,
newRecommendedRectJS.width,
newRecommendedRectJS.height);
var oldChildren = expectedChildren;
var newChildren = d.getRepositionChildren();
if (oldRecommendedRect != Qt.rect(0,0,0,0) && oldRecommendedRect != Qt.rect(0,0,1,1)
&& (oldRecommendedRect != newRecommendedRect
|| oldChildren != newChildren)
) {
expectedChildren = newChildren;
d.repositionAll();
}
recommendedRect = newRecommendedRect;
}
function findChild(item, name) {
for (var i = 0; i < item.children.length; ++i) {
if (item.children[i].objectName === name) {
return item.children[i];
}
}
return null;
}
function findParentMatching(item, predicate) {
while (item) {
if (predicate(item)) {
break;
}
item = item.parent;
}
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;
}
function isAlwaysOnTopWindow(window) {
return window.alwaysOnTop;
}
function isModalWindow(window) {
return window.modality !== Qt.NonModal;
}
function getTopLevelWindows(predicate) {
return findMatchingChildren(desktop, function(child) {
return (isTopLevelWindow(child) && (!predicate || predicate(child)));
});
}
function getDesktopWindow(item) {
return findParentMatching(item, isTopLevelWindow)
}
function fixupZOrder(windows, basis, topWindow) {
windows.sort(function(a, b){ return a.z - b.z; });
if ((topWindow.z >= basis) && (windows[windows.length - 1] === topWindow)) {
return;
}
var lastZ = -1;
var lastTargetZ = basis - 1;
for (var i = 0; i < windows.length; ++i) {
var window = windows[i];
if (!window.visible) {
continue
}
if (topWindow && (topWindow === window)) {
continue
}
if (window.z > lastZ) {
lastZ = window.z;
++lastTargetZ;
}
if (DebugQML) {
console.log("Assigning z order " + lastTargetZ + " to " + window)
}
window.z = lastTargetZ;
}
if (topWindow) {
++lastTargetZ;
if (DebugQML) {
console.log("Assigning z order " + lastTargetZ + " to " + topWindow)
}
topWindow.z = lastTargetZ;
}
return lastTargetZ;
}
function raiseWindow(targetWindow) {
var predicate;
var zBasis;
if (isModalWindow(targetWindow)) {
predicate = isModalWindow;
zBasis = zLevels.modal
} else if (isAlwaysOnTopWindow(targetWindow)) {
predicate = function(window) {
return (isAlwaysOnTopWindow(window) && !isModalWindow(window));
}
zBasis = zLevels.top
} else {
predicate = function(window) {
return (!isAlwaysOnTopWindow(window) && !isModalWindow(window));
}
zBasis = zLevels.normal
}
var windows = getTopLevelWindows(predicate);
fixupZOrder(windows, zBasis, targetWindow);
}
Component.onCompleted: {
//offscreenWindow.activeFocusItemChanged.connect(onWindowFocusChanged);
focusHack.start();
}
function onWindowFocusChanged() {
//console.log("Focus item is " + offscreenWindow.activeFocusItem);
// FIXME this needs more testing before it can go into production
// and I already cant produce any way to have a modal dialog lose focus
// to a non-modal one.
/*
var focusedWindow = getDesktopWindow(offscreenWindow.activeFocusItem);
if (isModalWindow(focusedWindow)) {
return;
}
// new focused window is not modal... check if there are any modal windows
var windows = getTopLevelWindows(isModalWindow);
if (0 === windows.length) {
return;
}
// There are modal windows present, force focus back to the top-most modal window
windows.sort(function(a, b){ return a.z - b.z; });
windows[windows.length - 1].focus = true;
*/
// var focusedItem = offscreenWindow.activeFocusItem ;
// if (DebugQML && focusedItem) {
// var rect = desktop.mapFromItem(focusedItem, 0, 0, focusedItem.width, focusedItem.height);
// focusDebugger.x = rect.x;
// focusDebugger.y = rect.y;
// focusDebugger.width = rect.width
// focusDebugger.height = rect.height
// }
}
function getRepositionChildren(predicate) {
return findMatchingChildren(desktop, function(child) {
return (child.shouldReposition === true && (!predicate || predicate(child)));
});
}
function repositionAll() {
if (desktop.repositionLocked) {
return;
}
var oldRecommendedRect = recommendedRect;
var oldRecommendedDimmensions = { x: oldRecommendedRect.width, y: oldRecommendedRect.height };
var newRecommendedRect = Controller.getRecommendedHUDRect();
var newRecommendedDimmensions = { x: newRecommendedRect.width, y: newRecommendedRect.height };
var windows = d.getTopLevelWindows();
for (var i = 0; i < windows.length; ++i) {
var targetWindow = windows[i];
if (targetWindow.visible) {
repositionWindow(targetWindow, true, oldRecommendedRect, oldRecommendedDimmensions, newRecommendedRect, newRecommendedDimmensions);
}
}
// also reposition the other children that aren't top level windows but want to be repositioned
var otherChildren = d.getRepositionChildren();
for (var i = 0; i < otherChildren.length; ++i) {
var child = otherChildren[i];
repositionWindow(child, true, oldRecommendedRect, oldRecommendedDimmensions, newRecommendedRect, newRecommendedDimmensions);
}
}
}
property bool pinned: false
property var hiddenChildren: []
function togglePinned() {
pinned = !pinned
}
function isPointOnWindow(point) {
for (var i = 0; i < desktop.visibleChildren.length; i++) {
var child = desktop.visibleChildren[i];
if (child.hasOwnProperty("modality")) {
var mappedPoint = mapToItem(child, point.x, point.y);
if (child.hasOwnProperty("frame")) {
var outLine = child.frame.children[2];
var framePoint = outLine.mapFromGlobal(point.x, point.y);
if (outLine.contains(framePoint)) {
return true;
}
}
if (child.contains(mappedPoint)) {
return true;
}
}
}
return false;
}
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) {
d.raiseWindow(desktop);
desktop.focus = true;
desktop.forceActiveFocus();
// recalculate our non-pinned children
hiddenChildren = d.findMatchingChildren(desktop, function(child){
return !d.isTopLevelWindow(child) && child.visible && !child.pinned;
});
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) {
console.warn("Could not find top level window for " + item);
return;
}
// Fix up the Z-order (takes into account if this is a modal window)
d.raiseWindow(targetWindow);
var setFocus = true;
if (!d.isModalWindow(targetWindow)) {
var modalWindows = d.getTopLevelWindows(d.isModalWindow);
if (modalWindows.length) {
setFocus = false;
}
}
if (setFocus) {
targetWindow.focus = true;
}
showDesktop();
}
function ensureTitleBarVisible(targetWindow) {
// Reposition window to ensure that title bar is vertically inside window.
if (targetWindow.frame && targetWindow.frame.decoration) {
var topMargin = -targetWindow.frame.decoration.anchors.topMargin; // Frame's topMargin is a negative value.
targetWindow.y = Math.max(targetWindow.y, topMargin);
}
}
function centerOnVisible(item) {
var targetWindow = d.getDesktopWindow(item);
if (!targetWindow) {
console.warn("Could not find top level window for " + item);
return;
}
if (typeof Controller === "undefined") {
console.warn("Controller not yet available... can't center");
return;
}
var newRecommendedRectJS = (typeof Controller === "undefined") ? Qt.rect(0,0,0,0) : Controller.getRecommendedHUDRect();
var newRecommendedRect = Qt.rect(newRecommendedRectJS.x, newRecommendedRectJS.y,
newRecommendedRectJS.width,
newRecommendedRectJS.height);
var newRecommendedDimmensions = { x: newRecommendedRect.width, y: newRecommendedRect.height };
var newX = newRecommendedRect.x + ((newRecommendedRect.width - targetWindow.width) / 2);
var newY = newRecommendedRect.y + ((newRecommendedRect.height - targetWindow.height) / 2);
targetWindow.x = newX;
targetWindow.y = newY;
ensureTitleBarVisible(targetWindow);
// If we've noticed that our recommended desktop rect has changed, record that change here.
if (recommendedRect != newRecommendedRect) {
recommendedRect = newRecommendedRect;
}
}
function repositionOnVisible(item) {
var targetWindow = d.getDesktopWindow(item);
if (!targetWindow) {
console.warn("Could not find top level window for " + item);
return;
}
if (typeof Controller === "undefined") {
console.warn("Controller not yet available... can't reposition targetWindow:" + targetWindow);
return;
}
var oldRecommendedRect = recommendedRect;
var oldRecommendedDimmensions = { x: oldRecommendedRect.width, y: oldRecommendedRect.height };
var newRecommendedRect = Controller.getRecommendedHUDRect();
var newRecommendedDimmensions = { x: newRecommendedRect.width, y: newRecommendedRect.height };
repositionWindow(targetWindow, false, oldRecommendedRect, oldRecommendedDimmensions, newRecommendedRect, newRecommendedDimmensions);
}
function repositionWindow(targetWindow, forceReposition,
oldRecommendedRect, oldRecommendedDimmensions, newRecommendedRect, newRecommendedDimmensions) {
if (desktop.width === 0 || desktop.height === 0) {
return;
}
if (!targetWindow) {
console.warn("Could not find top level window for " + item);
return;
}
var recommended = Controller.getRecommendedHUDRect();
var maxX = recommended.x + recommended.width;
var maxY = recommended.y + recommended.height;
var newPosition = Qt.vector2d(targetWindow.x, targetWindow.y);
// if we asked to force reposition, or if the window is completely outside of the recommended rectangle, reposition it
if (forceReposition || (targetWindow.x > maxX || (targetWindow.x + targetWindow.width) < recommended.x) ||
(targetWindow.y > maxY || (targetWindow.y + targetWindow.height) < recommended.y)) {
newPosition.x = -1
newPosition.y = -1
}
if (newPosition.x === -1 && newPosition.y === -1) {
var originRelativeX = (targetWindow.x - oldRecommendedRect.x);
var originRelativeY = (targetWindow.y - oldRecommendedRect.y);
if (isNaN(originRelativeX)) {
originRelativeX = 0;
}
if (isNaN(originRelativeY)) {
originRelativeY = 0;
}
var fractionX = Utils.clamp(originRelativeX / oldRecommendedDimmensions.x, 0, 1);
var fractionY = Utils.clamp(originRelativeY / oldRecommendedDimmensions.y, 0, 1);
var newX = (fractionX * newRecommendedDimmensions.x) + newRecommendedRect.x;
var newY = (fractionY * newRecommendedDimmensions.y) + newRecommendedRect.y;
newPosition = Qt.vector2d(newX, newY);
}
targetWindow.x = newPosition.x;
targetWindow.y = newPosition.y;
ensureTitleBarVisible(targetWindow);
}
Component { id: messageDialogBuilder; MessageDialog { } }
function messageBox(properties) {
return messageDialogBuilder.createObject(desktop, properties);
}
Component { id: inputDialogBuilder; QueryDialog { } }
function inputDialog(properties) {
return inputDialogBuilder.createObject(desktop, properties);
}
Component { id: customInputDialogBuilder; CustomQueryDialog { } }
function customInputDialog(properties) {
return customInputDialogBuilder.createObject(desktop, properties);
}
Component { id: fileDialogBuilder; FileDialog { } }
function fileDialog(properties) {
return fileDialogBuilder.createObject(desktop, properties);
}
Component { id: assetDialogBuilder; AssetDialog { } }
function assetDialog(properties) {
return assetDialogBuilder.createObject(desktop, properties);
}
function unfocusWindows() {
// First find the active focus item, and unfocus it, all the way
// up the parent chain to the window
var currentFocus = offscreenWindow.activeFocusItem;
var targetWindow = d.getDesktopWindow(currentFocus);
while (currentFocus) {
if (currentFocus === targetWindow) {
break;
}
currentFocus.focus = false;
currentFocus = currentFocus.parent;
}
// Unfocus all windows
var windows = d.getTopLevelWindows();
for (var i = 0; i < windows.length; ++i) {
windows[i].focus = false;
}
// For the desktop to have active focus
desktop.focus = true;
desktop.forceActiveFocus();
}
function openBrowserWindow(request, profile) {
var component = Qt.createComponent("../Browser.qml");
var newWindow = component.createObject(desktop);
newWindow.webView.profile = profile;
request.openIn(newWindow.webView);
}
FocusHack { id: focusHack; }
Rectangle {
id: focusDebugger;
objectName: "focusDebugger"
z: 9999; visible: false; color: "red"
ColorAnimation on color { from: "#7fffff00"; to: "#7f0000ff"; duration: 1000; loops: 9999 }
}
Action {
text: "Toggle Focus Debugger"
shortcut: "Ctrl+Shift+F"
enabled: DebugQML
onTriggered: focusDebugger.visible = !focusDebugger.visible
}
}

View file

@ -1,338 +0,0 @@
//
// CustomQueryDialog.qml
//
// Created by Zander Otavka on 7/14/16
// 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.7;
import QtQuick.Dialogs 1.2 as OriginalDialogs;
import QtQuick.Controls 1.4;
import "../controls-uit";
import "../styles-uit";
import "../windows";
ModalWindow {
id: root;
HifiConstants { id: hifi; }
implicitWidth: 640;
implicitHeight: 320;
visible: true;
keyboardOverride: true // Disable ModalWindow's keyboard.
signal selected(var result);
signal canceled();
property int icon: hifi.icons.none;
property string iconText: "";
property int iconSize: 35;
onIconChanged: updateIcon();
property var textInput;
property var comboBox;
property var checkBox;
onTextInputChanged: {
if (textInput && textInput.text !== undefined) {
textField.text = textInput.text;
}
}
onComboBoxChanged: {
if (comboBox && comboBox.index !== undefined) {
comboBoxField.currentIndex = comboBox.index;
}
}
onCheckBoxChanged: {
if (checkBox && checkBox.checked !== undefined) {
checkBoxField.checked = checkBox.checked;
}
}
property bool keyboardEnabled: false
property bool keyboardRaised: false
property bool punctuationMode: false
onKeyboardRaisedChanged: d.resize();
property var warning: "";
property var result;
property var implicitCheckState: null;
property int titleWidth: 0;
onTitleWidthChanged: d.resize();
function updateIcon() {
if (!root) {
return;
}
iconText = hifi.glyphForIcon(root.icon);
}
function updateCheckbox() {
if (checkBox.disableForItems) {
var currentItemInDisableList = false;
for (var i in checkBox.disableForItems) {
if (comboBoxField.currentIndex === checkBox.disableForItems[i]) {
currentItemInDisableList = true;
break;
}
}
if (currentItemInDisableList) {
checkBoxField.enabled = false;
if (checkBox.checkStateOnDisable !== null && checkBox.checkStateOnDisable !== undefined) {
root.implicitCheckState = checkBoxField.checked;
checkBoxField.checked = checkBox.checkStateOnDisable;
}
root.warning = checkBox.warningOnDisable;
} else {
checkBoxField.enabled = true;
if (root.implicitCheckState !== null) {
checkBoxField.checked = root.implicitCheckState;
root.implicitCheckState = null;
}
root.warning = "";
}
}
}
Item {
clip: true;
width: pane.width;
height: pane.height;
anchors.margins: 0;
QtObject {
id: d;
readonly property int minWidth: 480
readonly property int maxWdith: 1280
readonly property int minHeight: 120
readonly property int maxHeight: 720
function resize() {
var targetWidth = Math.max(titleWidth, pane.width);
var targetHeight = (textField.visible ? textField.controlHeight + hifi.dimensions.contentSpacing.y : 0) +
(extraInputs.visible ? extraInputs.height + hifi.dimensions.contentSpacing.y : 0) +
(buttons.height + 3 * hifi.dimensions.contentSpacing.y) +
((keyboardEnabled && keyboardRaised) ? (keyboard.raisedHeight + hifi.dimensions.contentSpacing.y) : 0);
root.width = (targetWidth < d.minWidth) ? d.minWidth : ((targetWidth > d.maxWdith) ? d.maxWidth : targetWidth);
root.height = (targetHeight < d.minHeight) ? d.minHeight : ((targetHeight > d.maxHeight) ?
d.maxHeight : targetHeight);
}
}
Item {
anchors {
top: parent.top;
bottom: extraInputs.visible ? extraInputs.top : buttons.top;
left: parent.left;
right: parent.right;
margins: 0;
}
// FIXME make a text field type that can be bound to a history for autocompletion
TextField {
id: textField;
label: root.textInput.label;
focus: root.textInput ? true : false;
visible: root.textInput ? true : false;
anchors {
left: parent.left;
right: parent.right;
bottom: keyboard.top;
bottomMargin: hifi.dimensions.contentSpacing.y;
}
}
Keyboard {
id: keyboard
raised: keyboardEnabled && keyboardRaised
numeric: punctuationMode
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
bottomMargin: raised ? hifi.dimensions.contentSpacing.y : 0
}
}
}
Item {
id: extraInputs;
visible: Boolean(root.checkBox || root.comboBox);
anchors {
left: parent.left;
right: parent.right;
bottom: buttons.top;
bottomMargin: hifi.dimensions.contentSpacing.y;
}
height: comboBoxField.controlHeight;
onHeightChanged: d.resize();
onWidthChanged: d.resize();
CheckBox {
id: checkBoxField;
text: root.checkBox.label;
focus: Boolean(root.checkBox);
visible: Boolean(root.checkBox);
anchors {
left: parent.left;
bottom: parent.bottom;
leftMargin: 6; // Magic number to align with warning icon
bottomMargin: 6;
}
}
ComboBox {
id: comboBoxField;
label: root.comboBox.label;
focus: Boolean(root.comboBox);
visible: Boolean(root.comboBox);
Binding on x {
when: comboBoxField.visible
value: !checkBoxField.visible ? buttons.x : acceptButton.x
}
Binding on width {
when: comboBoxField.visible
value: !checkBoxField.visible ? buttons.width : buttons.width - acceptButton.x
}
anchors {
right: parent.right;
bottom: parent.bottom;
}
model: root.comboBox ? root.comboBox.items : [];
onAccepted: {
updateCheckbox();
focus = true;
}
}
}
Row {
id: buttons;
focus: true;
spacing: hifi.dimensions.contentSpacing.x;
layoutDirection: Qt.RightToLeft;
onHeightChanged: d.resize();
onWidthChanged: {
d.resize();
resizeWarningText();
}
anchors {
bottom: parent.bottom;
left: parent.left;
right: parent.right;
bottomMargin: hifi.dimensions.contentSpacing.y;
}
function resizeWarningText() {
var rowWidth = buttons.width;
var buttonsWidth = acceptButton.width + cancelButton.width + hifi.dimensions.contentSpacing.x * 2;
var warningIconWidth = warningIcon.width + hifi.dimensions.contentSpacing.x;
warningText.width = rowWidth - buttonsWidth - warningIconWidth;
}
Button {
id: cancelButton;
action: cancelAction;
}
Button {
id: acceptButton;
action: acceptAction;
}
Text {
id: warningText;
visible: Boolean(root.warning);
text: root.warning;
wrapMode: Text.WordWrap;
font.italic: true;
maximumLineCount: 3;
}
HiFiGlyphs {
id: warningIcon;
visible: Boolean(root.warning);
text: hifi.glyphs.alert;
size: hifi.dimensions.controlLineHeight;
width: 20 // Line up with checkbox.
}
}
Action {
id: cancelAction;
text: qsTr("Cancel");
shortcut: "Esc";
onTriggered: {
root.result = null;
root.canceled();
// FIXME we are leaking memory to avoid a crash
// root.destroy();
root.disableFade = true
visible = false;
}
}
Action {
id: acceptAction;
text: qsTr("Add");
shortcut: "Return"
onTriggered: {
var result = {};
if (textInput) {
result.textInput = textField.text;
}
if (comboBox) {
result.comboBox = comboBoxField.currentIndex;
result.comboBoxText = comboBoxField.currentText;
}
if (checkBox) {
result.checkBox = checkBoxField.enabled ? checkBoxField.checked : null;
}
root.result = JSON.stringify(result);
root.selected(root.result);
// FIXME we are leaking memory to avoid a crash
// root.destroy();
root.disableFade = true
visible = false;
}
}
}
Keys.onPressed: {
if (!visible) {
return;
}
switch (event.key) {
case Qt.Key_Escape:
case Qt.Key_Back:
cancelAction.trigger();
event.accepted = true;
break;
case Qt.Key_Return:
case Qt.Key_Enter:
acceptAction.trigger();
event.accepted = true;
break;
}
}
Component.onCompleted: {
keyboardEnabled = HMD.active;
updateIcon();
updateCheckbox();
d.resize();
textField.forceActiveFocus();
}
}

View file

@ -1,840 +0,0 @@
//
// FileDialog.qml
//
// Created by Bradley Austin Davis on 14 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.7
import Qt.labs.folderlistmodel 2.1
import Qt.labs.settings 1.0
import QtQuick.Dialogs 1.2 as OriginalDialogs
import QtQuick.Controls 1.4
import ".."
import "../controls-uit"
import "../styles-uit"
import "../windows"
import "fileDialog"
//FIXME implement shortcuts for favorite location
ModalWindow {
id: root
resizable: true
implicitWidth: 480
implicitHeight: 360 + (fileDialogItem.keyboardEnabled && fileDialogItem.keyboardRaised ? keyboard.raisedHeight + hifi.dimensions.contentSpacing.y : 0)
minSize: Qt.vector2d(360, 240)
draggable: true
HifiConstants { id: hifi }
property var filesModel: ListModel { }
Settings {
category: "FileDialog"
property alias width: root.width
property alias height: root.height
property alias x: root.x
property alias y: root.y
}
// Set from OffscreenUi::getOpenFile()
property alias caption: root.title;
// Set from OffscreenUi::getOpenFile()
property alias dir: fileTableModel.folder;
// Set from OffscreenUi::getOpenFile()
property alias filter: selectionType.filtersString;
// Set from OffscreenUi::getOpenFile()
property int options; // <-- FIXME unused
property string iconText: root.title !== "" ? hifi.glyphs.scriptUpload : ""
property int iconSize: 40
property bool selectDirectory: false;
property bool showHidden: true;
// FIXME implement
property bool multiSelect: false;
property bool saveDialog: false;
property var helper: fileDialogHelper
property alias model: fileTableView.model
property var drives: helper.drives()
property int titleWidth: 0
signal selectedFile(var file);
signal canceled();
signal selected(int button);
function click(button) {
clickedButton = button;
selected(button);
destroy();
}
property int clickedButton: OriginalDialogs.StandardButton.NoButton;
Component.onCompleted: {
console.log("Helper " + helper + " drives " + drives);
fileDialogItem.keyboardEnabled = HMD.active;
// HACK: The following lines force the model to initialize properly such that the go-up button
// works properly from the initial screen.
var initialFolder = folderListModel.folder;
fileTableModel.folder = helper.pathToUrl(drives[0]);
fileTableModel.folder = initialFolder;
iconText = root.title !== "" ? hifi.glyphs.scriptUpload : "";
// Clear selection when click on external frame.
frameClicked.connect(function() { d.clearSelection(); });
if (selectDirectory) {
currentSelection.text = d.capitalizeDrive(helper.urlToPath(initialFolder));
d.currentSelectionIsFolder = true;
d.currentSelectionUrl = initialFolder;
}
helper.contentsChanged.connect(function() {
if (folderListModel) {
// Make folderListModel refresh.
var save = folderListModel.folder;
folderListModel.folder = "";
folderListModel.folder = save;
}
});
focusTimer.start();
}
Timer {
id: focusTimer
interval: 10
running: false
repeat: false
onTriggered: {
fileTableView.contentItem.forceActiveFocus();
}
}
Item {
id: fileDialogItem
clip: true
width: pane.width
height: pane.height
anchors.margins: 0
property bool keyboardEnabled: false
property bool keyboardRaised: false
property bool punctuationMode: false
MouseArea {
// Clear selection when click on internal unused area.
anchors.fill: parent
drag.target: root
onClicked: {
d.clearSelection();
// Defocus text field so that the keyboard gets hidden.
// Clicking also breaks keyboard navigation apart from backtabbing to cancel
frame.forceActiveFocus();
}
}
Row {
id: navControls
anchors {
top: parent.top
topMargin: hifi.dimensions.contentMargin.y
left: parent.left
}
spacing: hifi.dimensions.contentSpacing.x
GlyphButton {
id: upButton
glyph: hifi.glyphs.levelUp
width: height
size: 30
enabled: fileTableModel.parentFolder && fileTableModel.parentFolder !== ""
onClicked: d.navigateUp();
Keys.onReturnPressed: { d.navigateUp(); }
KeyNavigation.tab: homeButton
KeyNavigation.backtab: upButton
KeyNavigation.left: upButton
KeyNavigation.right: homeButton
}
GlyphButton {
id: homeButton
property var destination: helper.home();
glyph: hifi.glyphs.home
size: 28
width: height
enabled: d.homeDestination ? true : false
onClicked: d.navigateHome();
Keys.onReturnPressed: { d.navigateHome(); }
KeyNavigation.tab: fileTableView.contentItem
KeyNavigation.backtab: upButton
KeyNavigation.left: upButton
}
}
ComboBox {
id: pathSelector
anchors {
top: parent.top
topMargin: hifi.dimensions.contentMargin.y
left: navControls.right
leftMargin: hifi.dimensions.contentSpacing.x
right: parent.right
}
property var lastValidFolder: helper.urlToPath(fileTableModel.folder)
function calculatePathChoices(folder) {
var folders = folder.split("/"),
choices = [],
i, length;
if (folders[folders.length - 1] === "") {
folders.pop();
}
choices.push(folders[0]);
for (i = 1, length = folders.length; i < length; i++) {
choices.push(choices[i - 1] + "/" + folders[i]);
}
if (folders[0] === "") {
// Special handling for OSX root dir.
choices[0] = "/";
}
choices.reverse();
if (drives && drives.length > 1) {
choices.push("This PC");
}
if (choices.length > 0) {
pathSelector.model = choices;
}
}
onLastValidFolderChanged: {
var folder = d.capitalizeDrive(lastValidFolder);
calculatePathChoices(folder);
}
onCurrentTextChanged: {
var folder = currentText;
if (/^[a-zA-z]:$/.test(folder)) {
folder = "file:///" + folder + "/";
} else if (folder === "This PC") {
folder = "file:///";
} else {
folder = helper.pathToUrl(folder);
}
if (helper.urlToPath(folder).toLowerCase() !== helper.urlToPath(fileTableModel.folder).toLowerCase()) {
if (root.selectDirectory) {
currentSelection.text = currentText !== "This PC" ? currentText : "";
d.currentSelectionUrl = helper.pathToUrl(currentText);
}
fileTableModel.folder = folder;
}
}
KeyNavigation.up: fileTableView.contentItem
KeyNavigation.down: fileTableView.contentItem
KeyNavigation.tab: fileTableView.contentItem
KeyNavigation.backtab: fileTableView.contentItem
KeyNavigation.left: fileTableView.contentItem
KeyNavigation.right: fileTableView.contentItem
}
QtObject {
id: d
property var currentSelectionUrl;
readonly property string currentSelectionPath: helper.urlToPath(currentSelectionUrl);
property bool currentSelectionIsFolder;
property var backStack: []
property var tableViewConnection: Connections { target: fileTableView; onCurrentRowChanged: d.update(); }
property var modelConnection: Connections { target: fileTableModel; onFolderChanged: d.update(); }
property var homeDestination: helper.home();
function capitalizeDrive(path) {
// Consistently capitalize drive letter for Windows.
if (/[a-zA-Z]:/.test(path)) {
return path.charAt(0).toUpperCase() + path.slice(1);
}
return path;
}
function update() {
var row = fileTableView.currentRow;
if (row === -1) {
if (!root.selectDirectory) {
currentSelection.text = "";
currentSelectionIsFolder = false;
}
return;
}
currentSelectionUrl = helper.pathToUrl(fileTableView.model.get(row).filePath);
currentSelectionIsFolder = fileTableView.model !== filesModel ?
fileTableView.model.isFolder(row) :
fileTableModel.isFolder(row);
if (root.selectDirectory || !currentSelectionIsFolder) {
currentSelection.text = capitalizeDrive(helper.urlToPath(currentSelectionUrl));
} else {
currentSelection.text = "";
}
}
function navigateUp() {
if (fileTableModel.parentFolder && fileTableModel.parentFolder !== "") {
fileTableModel.folder = fileTableModel.parentFolder;
return true;
}
}
function navigateHome() {
fileTableModel.folder = homeDestination;
return true;
}
function clearSelection() {
fileTableView.selection.clear();
fileTableView.currentRow = -1;
update();
}
}
FolderListModel {
id: folderListModel
nameFilters: selectionType.currentFilter
showDirsFirst: true
showDotAndDotDot: false
showFiles: !root.selectDirectory
showHidden: root.showHidden
Component.onCompleted: {
showFiles = !root.selectDirectory
showHidden = root.showHidden
}
onFolderChanged: {
d.clearSelection();
fileTableModel.update(); // Update once the data from the folder change is available.
}
function getItem(index, field) {
return get(index, field);
}
}
ListModel {
// Emulates FolderListModel but contains drive data.
id: driveListModel
property int count: 1
Component.onCompleted: initialize();
function initialize() {
var drive,
i;
count = drives.length;
for (i = 0; i < count; i++) {
drive = drives[i].slice(0, -1); // Remove trailing "/".
append({
fileName: drive,
fileModified: new Date(0),
fileSize: 0,
filePath: drive + "/",
fileIsDir: true,
fileNameSort: drive.toLowerCase()
});
}
}
function getItem(index, field) {
return get(index)[field];
}
}
Component {
id: filesModelBuilder
ListModel { }
}
QtObject {
id: fileTableModel
// FolderListModel has a couple of problems:
// 1) Files and directories sort case-sensitively: https://bugreports.qt.io/browse/QTBUG-48757
// 2) Cannot browse up to the "computer" level to view Windows drives: https://bugreports.qt.io/browse/QTBUG-42901
//
// To solve these problems an intermediary ListModel is used that implements proper sorting and can be populated with
// drive information when viewing at the computer level.
property var folder
property int sortOrder: Qt.AscendingOrder
property int sortColumn: 0
property var model: folderListModel
property string parentFolder: calculateParentFolder();
readonly property string rootFolder: "file:///"
function calculateParentFolder() {
if (model === folderListModel) {
if (folderListModel.parentFolder.toString() === "" && driveListModel.count > 1) {
return rootFolder;
} else {
return folderListModel.parentFolder;
}
} else {
return "";
}
}
onFolderChanged: {
if (folder === rootFolder) {
model = driveListModel;
helper.monitorDirectory("");
update();
} else {
var needsUpdate = model === driveListModel && folder === folderListModel.folder;
model = folderListModel;
folderListModel.folder = folder;
helper.monitorDirectory(helper.urlToPath(folder));
if (needsUpdate) {
update();
}
}
}
function isFolder(row) {
if (row === -1) {
return false;
}
return filesModel.get(row).fileIsDir;
}
function get(row) {
return filesModel.get(row)
}
function update() {
var dataFields = ["fileName", "fileModified", "fileSize"],
sortFields = ["fileNameSort", "fileModified", "fileSize"],
dataField = dataFields[sortColumn],
sortField = sortFields[sortColumn],
sortValue,
fileName,
fileIsDir,
comparisonFunction,
lower,
middle,
upper,
rows = 0,
i;
filesModel = filesModelBuilder.createObject(root);
comparisonFunction = sortOrder === Qt.AscendingOrder
? function(a, b) { return a < b; }
: function(a, b) { return a > b; }
for (i = 0; i < model.count; i++) {
fileName = model.getItem(i, "fileName");
fileIsDir = model.getItem(i, "fileIsDir");
sortValue = model.getItem(i, dataField);
if (dataField === "fileName") {
// Directories first by prefixing a "*".
// Case-insensitive.
sortValue = (fileIsDir ? "*" : "") + sortValue.toLowerCase();
}
lower = 0;
upper = rows;
while (lower < upper) {
middle = Math.floor((lower + upper) / 2);
var lessThan;
if (comparisonFunction(sortValue, filesModel.get(middle)[sortField])) {
lessThan = true;
upper = middle;
} else {
lessThan = false;
lower = middle + 1;
}
}
filesModel.insert(lower, {
fileName: fileName,
fileModified: (fileIsDir ? new Date(0) : model.getItem(i, "fileModified")),
fileSize: model.getItem(i, "fileSize"),
filePath: model.getItem(i, "filePath"),
fileIsDir: fileIsDir,
fileNameSort: (fileIsDir ? "*" : "") + fileName.toLowerCase()
});
rows++;
}
}
}
Table {
id: fileTableView
colorScheme: hifi.colorSchemes.light
anchors {
top: navControls.bottom
topMargin: hifi.dimensions.contentSpacing.y
left: parent.left
right: parent.right
bottom: currentSelection.top
bottomMargin: hifi.dimensions.contentSpacing.y + currentSelection.controlHeight - currentSelection.height
}
headerVisible: !selectDirectory
onDoubleClicked: navigateToRow(row);
Keys.onReturnPressed: navigateToCurrentRow();
Keys.onEnterPressed: navigateToCurrentRow();
sortIndicatorColumn: 0
sortIndicatorOrder: Qt.AscendingOrder
sortIndicatorVisible: true
model: filesModel
function updateSort() {
fileTableModel.sortOrder = sortIndicatorOrder;
fileTableModel.sortColumn = sortIndicatorColumn;
fileTableModel.update();
}
onSortIndicatorColumnChanged: { updateSort(); }
onSortIndicatorOrderChanged: { updateSort(); }
itemDelegate: Item {
clip: true
FiraSansSemiBold {
text: getText();
elide: styleData.elideMode
anchors {
left: parent.left
leftMargin: hifi.dimensions.tablePadding
right: parent.right
rightMargin: hifi.dimensions.tablePadding
verticalCenter: parent.verticalCenter
}
size: hifi.fontSizes.tableText
color: hifi.colors.baseGrayHighlight
font.family: (styleData.row !== -1 && fileTableView.model.get(styleData.row).fileIsDir)
? "Fira Sans SemiBold" : "Fira Sans"
function getText() {
if (styleData.row === -1) {
return styleData.value;
}
switch (styleData.column) {
case 1: return fileTableView.model.get(styleData.row).fileIsDir ? "" : styleData.value;
case 2: return fileTableView.model.get(styleData.row).fileIsDir ? "" : formatSize(styleData.value);
default: return styleData.value;
}
}
function formatSize(size) {
var suffixes = [ "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" ];
var suffixIndex = 0
while ((size / 1024.0) > 1.1) {
size /= 1024.0;
++suffixIndex;
}
size = Math.round(size*1000)/1000;
size = size.toLocaleString()
return size + " " + suffixes[suffixIndex];
}
}
}
TableViewColumn {
id: fileNameColumn
role: "fileName"
title: "Name"
width: (selectDirectory ? 1.0 : 0.5) * fileTableView.width
movable: false
resizable: true
}
TableViewColumn {
id: fileModifiedColumn
role: "fileModified"
title: "Date"
width: 0.3 * fileTableView.width
movable: false
resizable: true
visible: !selectDirectory
}
TableViewColumn {
role: "fileSize"
title: "Size"
width: fileTableView.width - fileNameColumn.width - fileModifiedColumn.width
movable: false
resizable: true
visible: !selectDirectory
}
function navigateToRow(row) {
currentRow = row;
navigateToCurrentRow();
}
function navigateToCurrentRow() {
var currentModel = fileTableView.model !== filesModel ? fileTableView.model : fileTableModel
var row = fileTableView.currentRow
var isFolder = currentModel.isFolder(row);
var file = currentModel.get(row).filePath;
if (isFolder) {
currentModel.folder = helper.pathToUrl(file);
} else {
okAction.trigger();
}
}
property string prefix: ""
function addToPrefix(event) {
if (!event.text || event.text === "") {
return false;
}
var newPrefix = prefix + event.text.toLowerCase();
var matchedIndex = -1;
for (var i = 0; i < model.count; ++i) {
var name = model !== filesModel ? model.get(i).fileName.toLowerCase() :
filesModel.get(i).fileName.toLowerCase();
if (0 === name.indexOf(newPrefix)) {
matchedIndex = i;
break;
}
}
if (matchedIndex !== -1) {
fileTableView.selection.clear();
fileTableView.selection.select(matchedIndex);
fileTableView.currentRow = matchedIndex;
fileTableView.prefix = newPrefix;
}
prefixClearTimer.restart();
return true;
}
Timer {
id: prefixClearTimer
interval: 1000
repeat: false
running: false
onTriggered: fileTableView.prefix = "";
}
Keys.onPressed: {
switch (event.key) {
case Qt.Key_Backspace:
case Qt.Key_Tab:
case Qt.Key_Backtab:
event.accepted = false;
break;
case Qt.Key_Escape:
event.accepted = true;
root.click(OriginalDialogs.StandardButton.Cancel);
break;
default:
if (addToPrefix(event)) {
event.accepted = true
} else {
event.accepted = false;
}
break;
}
}
KeyNavigation.tab: root.saveDialog ? currentSelection : openButton
}
TextField {
id: currentSelection
label: selectDirectory ? "Directory:" : "File name:"
anchors {
left: parent.left
right: selectionType.visible ? selectionType.left: parent.right
rightMargin: selectionType.visible ? hifi.dimensions.contentSpacing.x : 0
bottom: keyboard.top
bottomMargin: hifi.dimensions.contentSpacing.y
}
readOnly: !root.saveDialog
activeFocusOnTab: !readOnly
onActiveFocusChanged: if (activeFocus) { selectAll(); }
onAccepted: okAction.trigger();
KeyNavigation.up: fileTableView.contentItem
KeyNavigation.down: openButton
KeyNavigation.tab: openButton
KeyNavigation.backtab: fileTableView.contentItem
}
FileTypeSelection {
id: selectionType
anchors {
top: currentSelection.top
left: buttonRow.left
right: parent.right
}
visible: !selectDirectory && filtersCount > 1
}
Keyboard {
id: keyboard
raised: parent.keyboardEnabled && parent.keyboardRaised
numeric: parent.punctuationMode
anchors {
left: parent.left
right: parent.right
bottom: buttonRow.top
bottomMargin: visible ? hifi.dimensions.contentSpacing.y : 0
}
}
Row {
id: buttonRow
anchors {
right: parent.right
bottom: parent.bottom
}
spacing: hifi.dimensions.contentSpacing.y
Button {
id: openButton
color: hifi.buttons.blue
action: okAction
Keys.onReturnPressed: okAction.trigger()
KeyNavigation.right: cancelButton
KeyNavigation.up: root.saveDialog ? currentSelection : fileTableView.contentItem
KeyNavigation.tab: cancelButton
}
Button {
id: cancelButton
action: cancelAction
Keys.onReturnPressed: { cancelAction.trigger() }
KeyNavigation.left: openButton
KeyNavigation.up: root.saveDialog ? currentSelection : fileTableView.contentItem
KeyNavigation.backtab: openButton
}
}
Action {
id: okAction
text: currentSelection.text ? (root.selectDirectory && fileTableView.currentRow === -1 ? "Choose" : (root.saveDialog ? "Save" : "Open")) : "Open"
enabled: currentSelection.text || !root.selectDirectory && d.currentSelectionIsFolder ? true : false
onTriggered: {
if (!root.selectDirectory && !d.currentSelectionIsFolder
|| root.selectDirectory && fileTableView.currentRow === -1) {
okActionTimer.start();
} else {
fileTableView.navigateToCurrentRow();
}
}
}
Timer {
id: okActionTimer
interval: 50
running: false
repeat: false
onTriggered: {
if (!root.saveDialog) {
selectedFile(d.currentSelectionUrl);
root.destroy()
return;
}
// Handle the ambiguity between different cases
// * typed name (with or without extension)
// * full path vs relative vs filename only
var selection = helper.saveHelper(currentSelection.text, root.dir, selectionType.currentFilter);
if (!selection) {
desktop.messageBox({ icon: OriginalDialogs.StandardIcon.Warning, text: "Unable to parse selection" })
return;
}
if (helper.urlIsDir(selection)) {
root.dir = selection;
currentSelection.text = "";
return;
}
// Check if the file is a valid target
if (!helper.urlIsWritable(selection)) {
desktop.messageBox({
icon: OriginalDialogs.StandardIcon.Warning,
text: "Unable to write to location " + selection
})
return;
}
if (helper.urlExists(selection)) {
var messageBox = desktop.messageBox({
icon: OriginalDialogs.StandardIcon.Question,
buttons: OriginalDialogs.StandardButton.Yes | OriginalDialogs.StandardButton.No,
text: "Do you wish to overwrite " + selection + "?",
});
var result = messageBox.exec();
if (OriginalDialogs.StandardButton.Yes !== result) {
return;
}
}
console.log("Selecting " + selection)
selectedFile(selection);
root.destroy();
}
}
Action {
id: cancelAction
text: "Cancel"
onTriggered: { canceled(); root.shown = false; }
}
}
Keys.onPressed: {
switch (event.key) {
case Qt.Key_Backspace:
event.accepted = d.navigateUp();
break;
case Qt.Key_Home:
event.accepted = d.navigateHome();
break;
case Qt.Key_Escape:
event.accepted = true;
root.click(OriginalDialogs.StandardButton.Cancel);
break;
}
}
}

View file

@ -1,231 +0,0 @@
//
// QueryDialog.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.7
import QtQuick.Controls 1.4
import "../controls-uit"
import "../styles-uit"
import "../windows"
ModalWindow {
id: root
HifiConstants { id: hifi }
implicitWidth: 640
implicitHeight: 320
visible: true
keyboardOverride: true // Disable ModalWindow's keyboard.
signal selected(var result);
signal canceled();
property int icon: hifi.icons.none
property string iconText: ""
property int iconSize: 35
onIconChanged: updateIcon();
property var items;
property string label
property var result;
property alias current: textResult.text
// For text boxes
property alias placeholderText: textResult.placeholderText
// For combo boxes
property bool editable: true;
property int titleWidth: 0
onTitleWidthChanged: d.resize();
property bool keyboardEnabled: false
property bool keyboardRaised: false
property bool punctuationMode: false
onKeyboardRaisedChanged: d.resize();
function updateIcon() {
if (!root) {
return;
}
iconText = hifi.glyphForIcon(root.icon);
}
Item {
id: modalWindowItem
clip: true
width: pane.width
height: pane.height
anchors.margins: 0
QtObject {
id: d
readonly property int minWidth: 480
readonly property int maxWdith: 1280
readonly property int minHeight: 120
readonly property int maxHeight: 720
function resize() {
var targetWidth = Math.max(titleWidth, pane.width)
var targetHeight = (items ? comboBox.controlHeight : textResult.controlHeight) + 5 * hifi.dimensions.contentSpacing.y + buttons.height
root.width = (targetWidth < d.minWidth) ? d.minWidth : ((targetWidth > d.maxWdith) ? d.maxWidth : targetWidth);
root.height = ((targetHeight < d.minHeight) ? d.minHeight : ((targetHeight > d.maxHeight) ? d.maxHeight : targetHeight)) + ((keyboardEnabled && keyboardRaised) ? (keyboard.raisedHeight + 2 * hifi.dimensions.contentSpacing.y) : 0)
}
}
Item {
anchors {
top: parent.top
bottom: keyboard.top;
left: parent.left;
right: parent.right;
margins: 0
bottomMargin: 2 * hifi.dimensions.contentSpacing.y
}
// FIXME make a text field type that can be bound to a history for autocompletion
TextField {
id: textResult
label: root.label
visible: items ? false : true
anchors {
left: parent.left;
right: parent.right;
bottom: parent.bottom
}
KeyNavigation.down: acceptButton
KeyNavigation.tab: acceptButton
}
ComboBox {
id: comboBox
label: root.label
visible: items ? true : false
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
}
model: items ? items : []
KeyNavigation.down: acceptButton
KeyNavigation.tab: acceptButton
}
}
property alias keyboardOverride: root.keyboardOverride
property alias keyboardRaised: root.keyboardRaised
property alias punctuationMode: root.punctuationMode
Keyboard {
id: keyboard
raised: keyboardEnabled && keyboardRaised
numeric: punctuationMode
anchors {
left: parent.left
right: parent.right
bottom: buttons.top
bottomMargin: raised ? 2 * hifi.dimensions.contentSpacing.y : 0
}
}
Flow {
id: buttons
spacing: hifi.dimensions.contentSpacing.x
onHeightChanged: d.resize(); onWidthChanged: d.resize();
layoutDirection: Qt.RightToLeft
anchors {
bottom: parent.bottom
right: parent.right
margins: 0
bottomMargin: hifi.dimensions.contentSpacing.y
}
Button {
id: cancelButton
action: cancelAction
KeyNavigation.left: acceptButton
KeyNavigation.up: items ? comboBox : textResult
KeyNavigation.backtab: acceptButton
}
Button {
id: acceptButton
action: acceptAction
KeyNavigation.right: cancelButton
KeyNavigation.up: items ? comboBox : textResult
KeyNavigation.tab: cancelButton
KeyNavigation.backtab: items ? comboBox : textResult
}
}
Action {
id: cancelAction
text: qsTr("Cancel");
shortcut: "Esc"
onTriggered: {
root.canceled();
// FIXME we are leaking memory to avoid a crash
// root.destroy();
root.disableFade = true
visible = false;
}
}
Action {
id: acceptAction
text: qsTr("OK");
shortcut: "Return"
onTriggered: {
root.result = items ? comboBox.currentText : textResult.text
root.selected(root.result);
// FIXME we are leaking memory to avoid a crash
// root.destroy();
root.disableFade = true
visible = false;
}
}
}
Keys.onPressed: {
if (!visible) {
return
}
switch (event.key) {
case Qt.Key_Escape:
case Qt.Key_Back:
cancelAction.trigger()
event.accepted = true;
break;
case Qt.Key_Return:
case Qt.Key_Enter:
if (acceptButton.focus) {
acceptAction.trigger()
} else if (cancelButton.focus) {
cancelAction.trigger()
} else if (comboBox.focus || comboBox.popup.focus) {
comboBox.showList()
}
event.accepted = true;
break;
}
}
Component.onCompleted: {
keyboardEnabled = HMD.active;
updateIcon();
d.resize();
if (items) {
comboBox.forceActiveFocus()
} else {
textResult.forceActiveFocus()
}
}
}

View file

@ -1,533 +0,0 @@
//
// AssetDialogContent.qml
//
// Created by David Rowe on 19 Apr 2017
// Copyright 2017 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.7
import QtQuick.Controls 1.5
import "../../controls-uit"
import "../../styles-uit"
import "../fileDialog"
Item {
// Set from OffscreenUi::assetDialog()
property alias dir: assetTableModel.folder
property alias filter: selectionType.filtersString // FIXME: Currently only supports simple filters, "*.xxx".
property int options // Not used.
property bool selectDirectory: false
// Not implemented.
//property bool saveDialog: false;
//property bool multiSelect: false;
property bool singleClickNavigate: false
HifiConstants { id: hifi }
Component.onCompleted: {
homeButton.destination = dir;
if (selectDirectory) {
d.currentSelectionIsFolder = true;
d.currentSelectionPath = assetTableModel.folder;
}
assetTableView.forceActiveFocus();
}
Item {
id: assetDialogItem
anchors.fill: parent
clip: true
MouseArea {
// Clear selection when click on internal unused area.
anchors.fill: parent
drag.target: root
onClicked: {
d.clearSelection();
frame.forceActiveFocus();
assetTableView.forceActiveFocus();
}
}
Row {
id: navControls
anchors {
top: parent.top
topMargin: hifi.dimensions.contentMargin.y
left: parent.left
}
spacing: hifi.dimensions.contentSpacing.x
GlyphButton {
id: upButton
glyph: hifi.glyphs.levelUp
width: height
size: 30
enabled: assetTableModel.parentFolder !== ""
onClicked: d.navigateUp();
}
GlyphButton {
id: homeButton
property string destination: ""
glyph: hifi.glyphs.home
size: 28
width: height
enabled: destination !== ""
//onClicked: d.navigateHome();
onClicked: assetTableModel.folder = destination;
}
}
ComboBox {
id: pathSelector
anchors {
top: parent.top
topMargin: hifi.dimensions.contentMargin.y
left: navControls.right
leftMargin: hifi.dimensions.contentSpacing.x
right: parent.right
}
z: 10
property string lastValidFolder: assetTableModel.folder
function calculatePathChoices(folder) {
var folders = folder.split("/"),
choices = [],
i, length;
if (folders[folders.length - 1] === "") {
folders.pop();
}
choices.push(folders[0]);
for (i = 1, length = folders.length; i < length; i++) {
choices.push(choices[i - 1] + "/" + folders[i]);
}
if (folders[0] === "") {
choices[0] = "/";
}
choices.reverse();
if (choices.length > 0) {
pathSelector.model = choices;
}
}
onLastValidFolderChanged: {
var folder = lastValidFolder;
calculatePathChoices(folder);
}
onCurrentTextChanged: {
var folder = currentText;
if (folder !== "/") {
folder += "/";
}
if (folder !== assetTableModel.folder) {
if (root.selectDirectory) {
currentSelection.text = currentText;
d.currentSelectionPath = currentText;
}
assetTableModel.folder = folder;
assetTableView.forceActiveFocus();
}
}
}
QtObject {
id: d
property string currentSelectionPath
property bool currentSelectionIsFolder
property var tableViewConnection: Connections { target: assetTableView; onCurrentRowChanged: d.update(); }
function update() {
var row = assetTableView.currentRow;
if (row === -1) {
if (!root.selectDirectory) {
currentSelection.text = "";
currentSelectionIsFolder = false;
}
return;
}
var rowInfo = assetTableModel.get(row);
currentSelectionPath = rowInfo.filePath;
currentSelectionIsFolder = rowInfo.fileIsDir;
if (root.selectDirectory || !currentSelectionIsFolder) {
currentSelection.text = currentSelectionPath;
} else {
currentSelection.text = "";
}
}
function navigateUp() {
if (assetTableModel.parentFolder !== "") {
assetTableModel.folder = assetTableModel.parentFolder;
return true;
}
return false;
}
function navigateHome() {
assetTableModel.folder = homeButton.destination;
return true;
}
function clearSelection() {
assetTableView.selection.clear();
assetTableView.currentRow = -1;
update();
}
}
ListModel {
id: assetTableModel
property string folder
property string parentFolder: ""
readonly property string rootFolder: "/"
onFolderChanged: {
parentFolder = calculateParentFolder();
update();
}
function calculateParentFolder() {
if (folder !== "/") {
return folder.slice(0, folder.slice(0, -1).lastIndexOf("/") + 1);
}
return "";
}
function isFolder(row) {
if (row === -1) {
return false;
}
return get(row).fileIsDir;
}
function onGetAllMappings(error, map) {
var mappings,
fileTypeFilter,
index,
path,
fileName,
fileType,
fileIsDir,
isValid,
subDirectory,
subDirectories = [],
fileNameSort,
rows = 0,
lower,
middle,
upper,
i,
length;
clear();
if (error === "") {
mappings = Object.keys(map);
fileTypeFilter = filter.replace("*", "").toLowerCase();
for (i = 0, length = mappings.length; i < length; i++) {
index = mappings[i].lastIndexOf("/");
path = mappings[i].slice(0, mappings[i].lastIndexOf("/") + 1);
fileName = mappings[i].slice(path.length);
fileType = fileName.slice(fileName.lastIndexOf("."));
fileIsDir = false;
isValid = false;
if (fileType.toLowerCase() === fileTypeFilter) {
if (path === folder) {
isValid = !selectDirectory;
} else if (path.length > folder.length) {
subDirectory = path.slice(folder.length);
index = subDirectory.indexOf("/");
if (index === subDirectory.lastIndexOf("/")) {
fileName = subDirectory.slice(0, index);
if (subDirectories.indexOf(fileName) === -1) {
fileIsDir = true;
isValid = true;
subDirectories.push(fileName);
}
}
}
}
if (isValid) {
fileNameSort = (fileIsDir ? "*" : "") + fileName.toLowerCase();
lower = 0;
upper = rows;
while (lower < upper) {
middle = Math.floor((lower + upper) / 2);
var lessThan;
if (fileNameSort < get(middle)["fileNameSort"]) {
lessThan = true;
upper = middle;
} else {
lessThan = false;
lower = middle + 1;
}
}
insert(lower, {
fileName: fileName,
filePath: path + (fileIsDir ? "" : fileName),
fileIsDir: fileIsDir,
fileNameSort: fileNameSort
});
rows++;
}
}
} else {
console.log("Error getting mappings from Asset Server");
}
}
function update() {
d.clearSelection();
clear();
Assets.getAllMappings(onGetAllMappings);
}
}
Table {
id: assetTableView
colorScheme: hifi.colorSchemes.light
anchors {
top: navControls.bottom
topMargin: hifi.dimensions.contentSpacing.y
left: parent.left
right: parent.right
bottom: currentSelection.top
bottomMargin: hifi.dimensions.contentSpacing.y + currentSelection.controlHeight - currentSelection.height
}
model: assetTableModel
focus: true
onClicked: {
if (singleClickNavigate) {
navigateToRow(row);
}
}
onDoubleClicked: navigateToRow(row);
Keys.onReturnPressed: navigateToCurrentRow();
Keys.onEnterPressed: navigateToCurrentRow();
itemDelegate: Item {
clip: true
FiraSansSemiBold {
text: styleData.value
elide: styleData.elideMode
anchors {
left: parent.left
leftMargin: hifi.dimensions.tablePadding
right: parent.right
rightMargin: hifi.dimensions.tablePadding
verticalCenter: parent.verticalCenter
}
size: hifi.fontSizes.tableText
color: hifi.colors.baseGrayHighlight
font.family: (styleData.row !== -1 && assetTableView.model.get(styleData.row).fileIsDir)
? "Fira Sans SemiBold" : "Fira Sans"
}
}
TableViewColumn {
id: fileNameColumn
role: "fileName"
title: "Name"
width: assetTableView.width
movable: false
resizable: false
}
function navigateToRow(row) {
currentRow = row;
navigateToCurrentRow();
}
function navigateToCurrentRow() {
if (model.isFolder(currentRow)) {
model.folder = model.get(currentRow).filePath;
} else {
okAction.trigger();
}
}
Timer {
id: prefixClearTimer
interval: 1000
repeat: false
running: false
onTriggered: assetTableView.prefix = "";
}
property string prefix: ""
function addToPrefix(event) {
if (!event.text || event.text === "") {
return false;
}
var newPrefix = prefix + event.text.toLowerCase();
var matchedIndex = -1;
for (var i = 0; i < model.count; ++i) {
var name = model.get(i).fileName.toLowerCase();
if (0 === name.indexOf(newPrefix)) {
matchedIndex = i;
break;
}
}
if (matchedIndex !== -1) {
assetTableView.selection.clear();
assetTableView.selection.select(matchedIndex);
assetTableView.currentRow = matchedIndex;
assetTableView.prefix = newPrefix;
}
prefixClearTimer.restart();
return true;
}
Keys.onPressed: {
switch (event.key) {
case Qt.Key_Backspace:
case Qt.Key_Tab:
case Qt.Key_Backtab:
event.accepted = false;
break;
default:
if (addToPrefix(event)) {
event.accepted = true
} else {
event.accepted = false;
}
break;
}
}
}
TextField {
id: currentSelection
label: selectDirectory ? "Directory:" : "File name:"
anchors {
left: parent.left
right: selectionType.visible ? selectionType.left: parent.right
rightMargin: selectionType.visible ? hifi.dimensions.contentSpacing.x : 0
bottom: buttonRow.top
bottomMargin: hifi.dimensions.contentSpacing.y
}
readOnly: true
activeFocusOnTab: !readOnly
onActiveFocusChanged: if (activeFocus) { selectAll(); }
onAccepted: okAction.trigger();
}
FileTypeSelection {
id: selectionType
anchors {
top: currentSelection.top
left: buttonRow.left
right: parent.right
}
visible: !selectDirectory && filtersCount > 1
KeyNavigation.left: assetTableView
KeyNavigation.right: openButton
}
Action {
id: okAction
text: currentSelection.text && root.selectDirectory && assetTableView.currentRow === -1 ? "Choose" : "Open"
enabled: currentSelection.text || !root.selectDirectory && d.currentSelectionIsFolder ? true : false
onTriggered: {
if (!root.selectDirectory && !d.currentSelectionIsFolder
|| root.selectDirectory && assetTableView.currentRow === -1) {
selectedAsset(d.currentSelectionPath);
root.destroy();
} else {
assetTableView.navigateToCurrentRow();
}
}
}
Action {
id: cancelAction
text: "Cancel"
onTriggered: {
canceled();
root.destroy();
}
}
Row {
id: buttonRow
anchors {
right: parent.right
bottom: parent.bottom
}
spacing: hifi.dimensions.contentSpacing.y
Button {
id: openButton
color: hifi.buttons.blue
action: okAction
Keys.onReturnPressed: okAction.trigger()
KeyNavigation.up: selectionType
KeyNavigation.left: selectionType
KeyNavigation.right: cancelButton
}
Button {
id: cancelButton
action: cancelAction
KeyNavigation.up: selectionType
KeyNavigation.left: openButton
KeyNavigation.right: assetTableView.contentItem
Keys.onReturnPressed: { canceled(); root.enabled = false }
}
}
}
Keys.onPressed: {
switch (event.key) {
case Qt.Key_Backspace:
event.accepted = d.navigateUp();
break;
case Qt.Key_Home:
event.accepted = d.navigateHome();
break;
}
}
}