mirror of
https://github.com/overte-org/overte.git
synced 2025-08-04 04:03:35 +02:00
messages and file dialogs in tablet
This commit is contained in:
parent
63a78a73db
commit
4a5be4238e
7 changed files with 1137 additions and 66 deletions
776
interface/resources/qml/dialogs/TabletFileDialog.qml
Normal file
776
interface/resources/qml/dialogs/TabletFileDialog.qml
Normal file
|
@ -0,0 +1,776 @@
|
||||||
|
//
|
||||||
|
// FileDialog.qml
|
||||||
|
//
|
||||||
|
// Created by Dante Ruiz on 23 Feb 2017
|
||||||
|
// 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 QtQuick.Controls 1.4
|
||||||
|
import Qt.labs.folderlistmodel 2.1
|
||||||
|
import Qt.labs.settings 1.0
|
||||||
|
import QtQuick.Controls.Styles 1.4
|
||||||
|
import QtQuick.Dialogs 1.2 as OriginalDialogs
|
||||||
|
|
||||||
|
import ".."
|
||||||
|
import "../controls-uit"
|
||||||
|
import "../styles-uit"
|
||||||
|
import "../windows"
|
||||||
|
|
||||||
|
import "fileDialog"
|
||||||
|
|
||||||
|
//FIXME implement shortcuts for favorite location
|
||||||
|
TabletModalWindow {
|
||||||
|
id: root
|
||||||
|
anchors.fill: parent
|
||||||
|
width: parent.width
|
||||||
|
height: parent.height
|
||||||
|
HifiConstants { id: hifi }
|
||||||
|
|
||||||
|
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: false;
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
fileTableView.forceActiveFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
TabletModalFrame {
|
||||||
|
id: fileDialogItem
|
||||||
|
width: parent.width
|
||||||
|
height: parent.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
|
||||||
|
onClicked: {
|
||||||
|
d.clearSelection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: navControls
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
topMargin: (fileDialogItem.hasTitle ? (fileDialogItem.frameMarginTop + hifi.dimensions.modalDialogMargin.y) : hifi.dimension.modalDialogMargin.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();
|
||||||
|
}
|
||||||
|
|
||||||
|
GlyphButton {
|
||||||
|
id: homeButton
|
||||||
|
property var destination: helper.home();
|
||||||
|
glyph: hifi.glyphs.home
|
||||||
|
size: 28
|
||||||
|
width: height
|
||||||
|
enabled: d.homeDestination ? true : false
|
||||||
|
onClicked: d.navigateHome();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*TabletComboBox {
|
||||||
|
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;
|
||||||
|
fileTableView.forceActiveFocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
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.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
|
||||||
|
Component.onCompleted: {
|
||||||
|
showFiles = !root.selectDirectory
|
||||||
|
}
|
||||||
|
|
||||||
|
onFolderChanged: {
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ListModel {
|
||||||
|
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 get(row).fileIsDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
clear();
|
||||||
|
|
||||||
|
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, get(middle)[sortField])) {
|
||||||
|
lessThan = true;
|
||||||
|
upper = middle;
|
||||||
|
} else {
|
||||||
|
lessThan = false;
|
||||||
|
lower = middle + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
|
||||||
|
d.clearSelection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
focus: true
|
||||||
|
Keys.onReturnPressed: navigateToCurrentRow();
|
||||||
|
Keys.onEnterPressed: navigateToCurrentRow();
|
||||||
|
|
||||||
|
sortIndicatorColumn: 0
|
||||||
|
sortIndicatorOrder: Qt.AscendingOrder
|
||||||
|
sortIndicatorVisible: true
|
||||||
|
|
||||||
|
model: fileTableModel
|
||||||
|
|
||||||
|
function updateSort() {
|
||||||
|
model.sortOrder = sortIndicatorOrder;
|
||||||
|
model.sortColumn = sortIndicatorColumn;
|
||||||
|
model.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
onSortIndicatorColumnChanged: { updateSort(); }
|
||||||
|
|
||||||
|
onSortIndicatorOrderChanged: { updateSort(); }
|
||||||
|
|
||||||
|
itemDelegate: Item {
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
//FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; }
|
||||||
|
//FontLoader { id: firaSansRegular; source: "../../fonts/FiraSans-Regular.ttf"; }
|
||||||
|
|
||||||
|
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)
|
||||||
|
//? firaSansSemiBold.name : firaSansRegular.name
|
||||||
|
|
||||||
|
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: fileMofifiedColumn
|
||||||
|
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 - fileMofifiedColumn.width
|
||||||
|
movable: false
|
||||||
|
resizable: true
|
||||||
|
visible: !selectDirectory
|
||||||
|
}
|
||||||
|
|
||||||
|
function navigateToRow(row) {
|
||||||
|
currentRow = row;
|
||||||
|
navigateToCurrentRow();
|
||||||
|
}
|
||||||
|
|
||||||
|
function navigateToCurrentRow() {
|
||||||
|
var row = fileTableView.currentRow
|
||||||
|
var isFolder = model.isFolder(row);
|
||||||
|
var file = model.get(row).filePath;
|
||||||
|
if (isFolder) {
|
||||||
|
fileTableView.model.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.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;
|
||||||
|
|
||||||
|
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: keyboard.top
|
||||||
|
bottomMargin: hifi.dimensions.contentSpacing.y
|
||||||
|
}
|
||||||
|
readOnly: !root.saveDialog
|
||||||
|
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: fileTableView
|
||||||
|
KeyNavigation.right: openButton
|
||||||
|
}
|
||||||
|
|
||||||
|
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.up: selectionType
|
||||||
|
KeyNavigation.left: selectionType
|
||||||
|
KeyNavigation.right: cancelButton
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: cancelButton
|
||||||
|
action: cancelAction
|
||||||
|
KeyNavigation.up: selectionType
|
||||||
|
KeyNavigation.left: openButton
|
||||||
|
KeyNavigation.right: fileTableView.contentItem
|
||||||
|
Keys.onReturnPressed: { canceled(); root.enabled = false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.destroy(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onPressed: {
|
||||||
|
switch (event.key) {
|
||||||
|
case Qt.Key_Backspace:
|
||||||
|
event.accepted = d.navigateUp();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Qt.Key_Home:
|
||||||
|
event.accepted = d.navigateHome();
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
248
interface/resources/qml/dialogs/TabletMessageBox.qml
Normal file
248
interface/resources/qml/dialogs/TabletMessageBox.qml
Normal file
|
@ -0,0 +1,248 @@
|
||||||
|
//
|
||||||
|
// MessageDialog.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 QtQuick.Dialogs 1.2 as OriginalDialogs
|
||||||
|
|
||||||
|
import "../controls-uit"
|
||||||
|
import "../styles-uit"
|
||||||
|
import "../windows"
|
||||||
|
|
||||||
|
import "messageDialog"
|
||||||
|
|
||||||
|
TabletModalWindow {
|
||||||
|
id: root
|
||||||
|
HifiConstants { id: hifi }
|
||||||
|
visible: true
|
||||||
|
|
||||||
|
signal selected(int button);
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: mouse;
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
|
|
||||||
|
function click(button) {
|
||||||
|
clickedButton = button;
|
||||||
|
selected(button);
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
function exec() {
|
||||||
|
return OffscreenUi.waitForMessageBoxResult(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
property alias detailedText: detailedText.text
|
||||||
|
property alias text: mainTextContainer.text
|
||||||
|
property alias informativeText: informativeTextContainer.text
|
||||||
|
property int buttons: OriginalDialogs.StandardButton.Ok
|
||||||
|
property int icon: OriginalDialogs.StandardIcon.NoIcon
|
||||||
|
property string iconText: ""
|
||||||
|
property int iconSize: 50
|
||||||
|
// onIconChanged: updateIcon();
|
||||||
|
property int defaultButton: OriginalDialogs.StandardButton.NoButton;
|
||||||
|
property int clickedButton: OriginalDialogs.StandardButton.NoButton;
|
||||||
|
//focus: defaultButton === OriginalDialogs.StandardButton.NoButton
|
||||||
|
|
||||||
|
property int titleWidth: 0
|
||||||
|
onTitleWidthChanged: d.resize();
|
||||||
|
|
||||||
|
function updateIcon() {
|
||||||
|
if (!root) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
iconText = hifi.glyphForIcon(root.icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
TabletModalFrame {
|
||||||
|
id: messageBox
|
||||||
|
clip: true
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
width: parent.width
|
||||||
|
height: 300
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: d
|
||||||
|
readonly property int minWidth: 200
|
||||||
|
readonly property int maxWidth: 1280
|
||||||
|
readonly property int minHeight: 120
|
||||||
|
readonly property int maxHeight: 720
|
||||||
|
|
||||||
|
function resize() {
|
||||||
|
console.log("[DR]-> setting the target height");
|
||||||
|
var targetWidth = Math.max(titleWidth, mainTextContainer.contentWidth)
|
||||||
|
var targetHeight = mainTextContainer.height + 3 * hifi.dimensions.contentSpacing.y
|
||||||
|
+ (informativeTextContainer.text != "" ? informativeTextContainer.contentHeight + 3 * hifi.dimensions.contentSpacing.y : 0)
|
||||||
|
+ buttons.height
|
||||||
|
+ (details.implicitHeight + hifi.dimensions.contentSpacing.y) + messageBox.frameMarginTop
|
||||||
|
//messageBox.width = (targetWidth < d.minWidth) ? d.minWidth : ((targetWidth > d.maxWidth) ? d.maxWidth : targetWidth)
|
||||||
|
|
||||||
|
console.log("[DR} -> about to set the height");
|
||||||
|
messageBox.height = (targetHeight < d.minHeight) ? d.minHeight: ((targetHeight > d.maxHeight) ? d.maxHeight : targetHeight)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RalewaySemiBold {
|
||||||
|
id: mainTextContainer
|
||||||
|
onTextChanged: d.resize();
|
||||||
|
wrapMode: Text.WrapAnywhere
|
||||||
|
size: hifi.fontSizes.sectionName
|
||||||
|
color: hifi.colors.baseGrayHighlight
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
horizontalCenter: parent.horizontalCenter
|
||||||
|
margins: 0
|
||||||
|
topMargin: hifi.dimensions.contentSpacing.y + messageBox.frameMarginTop
|
||||||
|
}
|
||||||
|
lineHeight: 2
|
||||||
|
lineHeightMode: Text.ProportionalHeight
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
RalewaySemiBold {
|
||||||
|
id: informativeTextContainer
|
||||||
|
onTextChanged: d.resize();
|
||||||
|
wrapMode: Text.WrapAnywhere
|
||||||
|
size: hifi.fontSizes.sectionName
|
||||||
|
color: hifi.colors.baseGrayHighlight
|
||||||
|
anchors {
|
||||||
|
top: mainTextContainer.bottom
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
margins: 0
|
||||||
|
topMargin: text != "" ? hifi.dimensions.contentSpacing.y : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Flow {
|
||||||
|
id: buttons
|
||||||
|
focus: true
|
||||||
|
spacing: hifi.dimensions.contentSpacing.x
|
||||||
|
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||||
|
layoutDirection: Qt.RightToLeft
|
||||||
|
anchors {
|
||||||
|
top: informativeTextContainer.text == "" ? mainTextContainer.bottom : informativeTextContainer.bottom
|
||||||
|
horizontalCenter: parent.horizontalCenter
|
||||||
|
margins: 0
|
||||||
|
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
||||||
|
}
|
||||||
|
MessageDialogButton { dialog: root; text: qsTr("Close"); button: OriginalDialogs.StandardButton.Close; }
|
||||||
|
MessageDialogButton { dialog: root; text: qsTr("Abort"); button: OriginalDialogs.StandardButton.Abort; }
|
||||||
|
MessageDialogButton { dialog: root; text: qsTr("Cancel"); button: OriginalDialogs.StandardButton.Cancel; }
|
||||||
|
MessageDialogButton { dialog: root; text: qsTr("Restore Defaults"); button: OriginalDialogs.StandardButton.RestoreDefaults; }
|
||||||
|
MessageDialogButton { dialog: root; text: qsTr("Reset"); button: OriginalDialogs.StandardButton.Reset; }
|
||||||
|
MessageDialogButton { dialog: root; text: qsTr("Discard"); button: OriginalDialogs.StandardButton.Discard; }
|
||||||
|
MessageDialogButton { dialog: root; text: qsTr("No to All"); button: OriginalDialogs.StandardButton.NoToAll; }
|
||||||
|
MessageDialogButton { dialog: root; text: qsTr("No"); button: OriginalDialogs.StandardButton.No; }
|
||||||
|
MessageDialogButton { dialog: root; text: qsTr("Yes to All"); button: OriginalDialogs.StandardButton.YesToAll; }
|
||||||
|
MessageDialogButton { dialog: root; text: qsTr("Yes"); button: OriginalDialogs.StandardButton.Yes; }
|
||||||
|
MessageDialogButton { dialog: root; text: qsTr("Apply"); button: OriginalDialogs.StandardButton.Apply; }
|
||||||
|
MessageDialogButton { dialog: root; text: qsTr("Ignore"); button: OriginalDialogs.StandardButton.Ignore; }
|
||||||
|
MessageDialogButton { dialog: root; text: qsTr("Retry"); button: OriginalDialogs.StandardButton.Retry; }
|
||||||
|
MessageDialogButton { dialog: root; text: qsTr("Save All"); button: OriginalDialogs.StandardButton.SaveAll; }
|
||||||
|
MessageDialogButton { dialog: root; text: qsTr("Save"); button: OriginalDialogs.StandardButton.Save; }
|
||||||
|
MessageDialogButton { dialog: root; text: qsTr("Open"); button: OriginalDialogs.StandardButton.Open; }
|
||||||
|
MessageDialogButton { dialog: root; text: qsTr("OK"); button: OriginalDialogs.StandardButton.Ok; }
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: moreButton
|
||||||
|
text: qsTr("Show Details...")
|
||||||
|
width: 160
|
||||||
|
onClicked: { content.state = (content.state === "" ? "expanded" : "") }
|
||||||
|
visible: detailedText && detailedText.length > 0
|
||||||
|
}
|
||||||
|
MessageDialogButton { dialog: root; text: qsTr("Help"); button: OriginalDialogs.StandardButton.Help; }
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: details
|
||||||
|
width: parent.width
|
||||||
|
implicitHeight: detailedText.implicitHeight
|
||||||
|
height: 0
|
||||||
|
clip: true
|
||||||
|
anchors {
|
||||||
|
top: buttons.bottom
|
||||||
|
left: parent.left;
|
||||||
|
right: parent.right;
|
||||||
|
margins: 0
|
||||||
|
topMargin: hifi.dimensions.contentSpacing.y
|
||||||
|
}
|
||||||
|
Flickable {
|
||||||
|
id: flickable
|
||||||
|
contentHeight: detailedText.height
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.topMargin: hifi.dimensions.contentSpacing.x
|
||||||
|
anchors.bottomMargin: hifi.dimensions.contentSpacing.y
|
||||||
|
TextEdit {
|
||||||
|
id: detailedText
|
||||||
|
size: hifi.fontSizes.menuItem
|
||||||
|
color: hifi.colors.baseGrayHighlight
|
||||||
|
width: details.width
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
readOnly: true
|
||||||
|
selectByMouse: true
|
||||||
|
anchors.margins: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: "expanded"
|
||||||
|
PropertyChanges { target: root; anchors.fill: undefined }
|
||||||
|
PropertyChanges { target: details; height: 120 }
|
||||||
|
PropertyChanges { target: moreButton; text: qsTr("Hide Details") }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
updateIcon();
|
||||||
|
d.resize();
|
||||||
|
}
|
||||||
|
onStateChanged: d.resize()
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onPressed: {
|
||||||
|
if (!visible) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.modifiers === Qt.ControlModifier)
|
||||||
|
switch (event.key) {
|
||||||
|
case Qt.Key_A:
|
||||||
|
event.accepted = true
|
||||||
|
detailedText.selectAll()
|
||||||
|
break
|
||||||
|
case Qt.Key_C:
|
||||||
|
event.accepted = true
|
||||||
|
detailedText.copy()
|
||||||
|
break
|
||||||
|
case Qt.Key_Period:
|
||||||
|
if (Qt.platform.os === "osx") {
|
||||||
|
event.accepted = true
|
||||||
|
content.reject()
|
||||||
|
}
|
||||||
|
break
|
||||||
|
} else switch (event.key) {
|
||||||
|
case Qt.Key_Escape:
|
||||||
|
case Qt.Key_Back:
|
||||||
|
event.accepted = true
|
||||||
|
root.click(OriginalDialogs.StandardButton.Cancel)
|
||||||
|
break
|
||||||
|
|
||||||
|
case Qt.Key_Enter:
|
||||||
|
case Qt.Key_Return:
|
||||||
|
event.accepted = true
|
||||||
|
root.click(root.defaultButton)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -61,10 +61,10 @@ TabletModalWindow {
|
||||||
iconText = hifi.glyphForIcon(root.icon);
|
iconText = hifi.glyphForIcon(root.icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
TabletModalFrame {
|
||||||
id: modalWindowItem
|
id: modalWindowItem
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 480
|
height: 240
|
||||||
anchors.margins: 0
|
anchors.margins: 0
|
||||||
anchors {
|
anchors {
|
||||||
verticalCenter: parent.verticalCenter
|
verticalCenter: parent.verticalCenter
|
||||||
|
@ -82,13 +82,13 @@ TabletModalWindow {
|
||||||
var targetWidth = Math.max(titleWidth, 480)
|
var targetWidth = Math.max(titleWidth, 480)
|
||||||
var targetHeight = (items ? comboBox.controlHeight : textResult.controlHeight) + 5 * hifi.dimensions.contentSpacing.y + buttons.height
|
var targetHeight = (items ? comboBox.controlHeight : textResult.controlHeight) + 5 * hifi.dimensions.contentSpacing.y + buttons.height
|
||||||
modalWindowItem.width = (targetWidth < d.minWidth) ? d.minWidth : ((targetWidth > d.maxWdith) ? d.maxWidth : targetWidth);
|
modalWindowItem.width = (targetWidth < d.minWidth) ? d.minWidth : ((targetWidth > d.maxWdith) ? d.maxWidth : targetWidth);
|
||||||
modalWindowItem.height = ((targetHeight < d.minHeight) ? d.minHeight : ((targetHeight > d.maxHeight) ? d.maxHeight : targetHeight)) + ((keyboardEnabled && keyboardRaised) ? (keyboard.raisedHeight + 2 * hifi.dimensions.contentSpacing.y) : 0)
|
modalWindowItem.height = ((targetHeight < d.minHeight) ? d.minHeight : ((targetHeight > d.maxHeight) ? d.maxHeight : targetHeight)) + ((keyboardEnabled && keyboardRaised) ? (keyboard.raisedHeight + 2 * hifi.dimensions.contentSpacing.y) : 0) + modalWindowItem.frameMarginTop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
anchors {
|
anchors {
|
||||||
top: frameTitle.bottom
|
top: parent.top
|
||||||
bottom: keyboard.top;
|
bottom: keyboard.top;
|
||||||
left: parent.left;
|
left: parent.left;
|
||||||
right: parent.right;
|
right: parent.right;
|
||||||
|
|
|
@ -17,7 +17,7 @@ import "../../styles-uit"
|
||||||
import "../../controls-uit" as HifiControls
|
import "../../controls-uit" as HifiControls
|
||||||
import "../../windows"
|
import "../../windows"
|
||||||
|
|
||||||
Item {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
objectName: "RunningScripts"
|
objectName: "RunningScripts"
|
||||||
HifiConstants { id: hifi }
|
HifiConstants { id: hifi }
|
||||||
|
@ -28,6 +28,8 @@ Item {
|
||||||
property var runningScriptsModel: ListModel { }
|
property var runningScriptsModel: ListModel { }
|
||||||
property bool isHMD: false
|
property bool isHMD: false
|
||||||
|
|
||||||
|
color: hifi.colors.baseGray
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: ScriptDiscoveryService
|
target: ScriptDiscoveryService
|
||||||
onScriptCountChanged: updateRunningScripts();
|
onScriptCountChanged: updateRunningScripts();
|
||||||
|
|
|
@ -9,6 +9,7 @@ Item {
|
||||||
property var eventBridge;
|
property var eventBridge;
|
||||||
|
|
||||||
property var rootMenu;
|
property var rootMenu;
|
||||||
|
property var openModal: null;
|
||||||
property string subMenu: ""
|
property string subMenu: ""
|
||||||
signal showDesktop();
|
signal showDesktop();
|
||||||
|
|
||||||
|
@ -18,16 +19,22 @@ Item {
|
||||||
|
|
||||||
Component { id: inputDialogBuilder; TabletQueryDialog { } }
|
Component { id: inputDialogBuilder; TabletQueryDialog { } }
|
||||||
function inputDialog(properties) {
|
function inputDialog(properties) {
|
||||||
return inputDialogBuilder.createObject(tabletRoot, properties);
|
openModal = inputDialogBuilder.createObject(tabletRoot, properties);
|
||||||
|
return openModal;
|
||||||
}
|
}
|
||||||
|
Component { id: messageBoxBuilder; TabletMessageBox { } }
|
||||||
function messageBox(properties) {
|
function messageBox(properties) {
|
||||||
|
openModal = messageBoxBuilder.createObject(tabletRoot, properties);
|
||||||
|
return openModal;
|
||||||
}
|
}
|
||||||
|
|
||||||
function customInputDialog(properties) {
|
function customInputDialog(properties) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component { id: fileDialogBuilder; TabletFileDialog { } }
|
||||||
function fileDialog(properties) {
|
function fileDialog(properties) {
|
||||||
|
openModal = fileDialogBuilder.createObject(tabletRoot, properties);
|
||||||
|
return openModal;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setMenuProperties(rootMenu, subMenu) {
|
function setMenuProperties(rootMenu, subMenu) {
|
||||||
|
@ -104,6 +111,12 @@ Item {
|
||||||
loader.item.setRootMenu(tabletRoot.rootMenu, tabletRoot.subMenu);
|
loader.item.setRootMenu(tabletRoot.rootMenu, tabletRoot.subMenu);
|
||||||
}
|
}
|
||||||
loader.item.forceActiveFocus();
|
loader.item.forceActiveFocus();
|
||||||
|
|
||||||
|
if (openModal) {
|
||||||
|
openModal.canceled();
|
||||||
|
openModal.destroy();
|
||||||
|
openModal = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,68 +18,69 @@ import "../styles-uit"
|
||||||
Rectangle {
|
Rectangle {
|
||||||
HifiConstants { id: hifi }
|
HifiConstants { id: hifi }
|
||||||
|
|
||||||
|
id: frameContent
|
||||||
|
|
||||||
Rectangle {
|
readonly property bool hasTitle: root.title != ""
|
||||||
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
|
||||||
|
|
||||||
readonly property int frameMarginLeft: hifi.dimensions.modalDialogMargin.x
|
border {
|
||||||
readonly property int frameMarginRight: hifi.dimensions.modalDialogMargin.x
|
width: hifi.dimensions.borderWidth
|
||||||
readonly property int frameMarginTop: hifi.dimensions.modalDialogMargin.y + (frameContent.hasTitle ? hifi.dimensions.modalDialogTitleHeight + 10 : 0)
|
color: hifi.colors.lightGrayText80
|
||||||
readonly property int frameMarginBottom: hifi.dimensions.modalDialogMargin.y
|
|
||||||
|
|
||||||
border {
|
|
||||||
width: hifi.dimensions.borderWidth
|
|
||||||
color: hifi.colors.lightGrayText80
|
|
||||||
}
|
}
|
||||||
|
|
||||||
radius: hifi.dimensions.borderRadius
|
radius: hifi.dimensions.borderRadius
|
||||||
color: hifi.colors.faintGray
|
color: hifi.colors.faintGray
|
||||||
|
Item {
|
||||||
|
id: frameTitle
|
||||||
|
visible: frameContent.hasTitle
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
fill: parent
|
||||||
|
topMargin: frameMarginTop
|
||||||
|
leftMargin: frameMarginLeft
|
||||||
|
rightMargin: frameMarginRight
|
||||||
|
//bottomMargin: frameMarginBottom
|
||||||
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: frameTitle
|
width: title.width + (icon.text !== "" ? icon.width + hifi.dimensions.contentSpacing.x : 20)
|
||||||
visible: true//frameContent.hasTitle
|
|
||||||
//anchors.fill: parent
|
|
||||||
|
|
||||||
anchors {
|
|
||||||
fill: parent
|
|
||||||
topMargin: -frameMarginTop
|
|
||||||
leftMargin: -frameMarginLeft
|
|
||||||
rightMargin: -frameMarginRight
|
|
||||||
bottomMargin: -frameMarginBottom
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
onWidthChanged: root.titleWidth = width
|
||||||
width: title.width + (icon.text !== "" ? icon.width + hifi.dimensions.contentSpacing.x : 20)
|
|
||||||
|
HiFiGlyphs {
|
||||||
onWidthChanged: root.titleWidth = width
|
id: icon
|
||||||
|
text: root.iconText ? root.iconText : ""
|
||||||
HiFiGlyphs {
|
size: root.iconSize ? root.iconSize : 30
|
||||||
id: icon
|
color: hifi.colors.lightGray
|
||||||
text: root.iconText ? root.iconText : "hello"
|
visible: true
|
||||||
size: root.iconSize ? root.iconSize : 30
|
anchors.verticalCenter: title.verticalCenter
|
||||||
color: hifi.colors.lightGray
|
anchors.leftMargin: 50
|
||||||
visible: true
|
anchors.left: parent.left
|
||||||
anchors.verticalCenter: title.verticalCenter
|
|
||||||
anchors.left: parent.left
|
|
||||||
}
|
|
||||||
RalewayRegular {
|
|
||||||
id: title
|
|
||||||
text: root.title
|
|
||||||
elide: Text.ElideRight
|
|
||||||
color: hifi.colors.baseGrayHighlight
|
|
||||||
size: hifi.fontSizes.overlayTitle
|
|
||||||
y: -hifi.dimensions.modalDialogTitleHeight
|
|
||||||
anchors.right: parent.right
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
RalewayRegular {
|
||||||
anchors.left: parent.left
|
id: title
|
||||||
|
text: root.title
|
||||||
|
elide: Text.ElideRight
|
||||||
|
color: hifi.colors.baseGrayHighlight
|
||||||
|
size: hifi.fontSizes.overlayTitle
|
||||||
|
y: -hifi.dimensions.modalDialogTitleHeight
|
||||||
|
anchors.rightMargin: -50
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
height: 1
|
|
||||||
color: hifi.colors.lightGray
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
height: 1
|
||||||
|
color: hifi.colors.lightGray
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -211,9 +211,19 @@ QQuickItem* OffscreenUi::createMessageBox(Icon icon, const QString& title, const
|
||||||
map.insert("buttons", buttons.operator int());
|
map.insert("buttons", buttons.operator int());
|
||||||
map.insert("defaultButton", defaultButton);
|
map.insert("defaultButton", defaultButton);
|
||||||
QVariant result;
|
QVariant result;
|
||||||
bool invokeResult = QMetaObject::invokeMethod(_desktop, "messageBox",
|
bool invokeResult;
|
||||||
Q_RETURN_ARG(QVariant, result),
|
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||||
Q_ARG(QVariant, QVariant::fromValue(map)));
|
TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
|
||||||
|
if (tablet->getToolbarMode()) {
|
||||||
|
invokeResult = QMetaObject::invokeMethod(_desktop, "messageBox",
|
||||||
|
Q_RETURN_ARG(QVariant, result),
|
||||||
|
Q_ARG(QVariant, QVariant::fromValue(map)));
|
||||||
|
} else {
|
||||||
|
QQuickItem* tabletRoot = tablet->getTabletRoot();
|
||||||
|
invokeResult = QMetaObject::invokeMethod(tabletRoot, "messageBox",
|
||||||
|
Q_RETURN_ARG(QVariant, result),
|
||||||
|
Q_ARG(QVariant, QVariant::fromValue(map)));
|
||||||
|
}
|
||||||
|
|
||||||
if (!invokeResult) {
|
if (!invokeResult) {
|
||||||
qWarning() << "Failed to create message box";
|
qWarning() << "Failed to create message box";
|
||||||
|
@ -434,10 +444,21 @@ QQuickItem* OffscreenUi::createCustomInputDialog(const Icon icon, const QString&
|
||||||
map.insert("title", title);
|
map.insert("title", title);
|
||||||
map.insert("icon", icon);
|
map.insert("icon", icon);
|
||||||
QVariant result;
|
QVariant result;
|
||||||
bool invokeResult = QMetaObject::invokeMethod(_desktop, "customInputDialog",
|
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||||
Q_RETURN_ARG(QVariant, result),
|
TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
|
||||||
Q_ARG(QVariant, QVariant::fromValue(map)));
|
|
||||||
|
|
||||||
|
bool invokeResult;
|
||||||
|
if (tablet->getToolbarMode()) {
|
||||||
|
invokeResult = QMetaObject::invokeMethod(_desktop, "inputDialog",
|
||||||
|
Q_RETURN_ARG(QVariant, result),
|
||||||
|
Q_ARG(QVariant, QVariant::fromValue(map)));
|
||||||
|
} else {
|
||||||
|
QQuickItem* tabletRoot = tablet->getTabletRoot();
|
||||||
|
invokeResult = QMetaObject::invokeMethod(tabletRoot, "inputDialog",
|
||||||
|
Q_RETURN_ARG(QVariant, result),
|
||||||
|
Q_ARG(QVariant, QVariant::fromValue(map)));
|
||||||
|
}
|
||||||
|
|
||||||
if (!invokeResult) {
|
if (!invokeResult) {
|
||||||
qWarning() << "Failed to create custom message box";
|
qWarning() << "Failed to create custom message box";
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -581,9 +602,19 @@ private slots:
|
||||||
|
|
||||||
QString OffscreenUi::fileDialog(const QVariantMap& properties) {
|
QString OffscreenUi::fileDialog(const QVariantMap& properties) {
|
||||||
QVariant buildDialogResult;
|
QVariant buildDialogResult;
|
||||||
bool invokeResult = QMetaObject::invokeMethod(_desktop, "fileDialog",
|
bool invokeResult;
|
||||||
Q_RETURN_ARG(QVariant, buildDialogResult),
|
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||||
Q_ARG(QVariant, QVariant::fromValue(properties)));
|
TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
|
||||||
|
if (tablet->getToolbarMode()) {
|
||||||
|
invokeResult = QMetaObject::invokeMethod(_desktop, "fileDialog",
|
||||||
|
Q_RETURN_ARG(QVariant, buildDialogResult),
|
||||||
|
Q_ARG(QVariant, QVariant::fromValue(properties)));
|
||||||
|
} else {
|
||||||
|
QQuickItem* tabletRoot = tablet->getTabletRoot();
|
||||||
|
invokeResult = QMetaObject::invokeMethod(tabletRoot, "fileDialog",
|
||||||
|
Q_RETURN_ARG(QVariant, buildDialogResult),
|
||||||
|
Q_ARG(QVariant, QVariant::fromValue(properties)));
|
||||||
|
}
|
||||||
|
|
||||||
if (!invokeResult) {
|
if (!invokeResult) {
|
||||||
qWarning() << "Failed to create file open dialog";
|
qWarning() << "Failed to create file open dialog";
|
||||||
|
|
Loading…
Reference in a new issue