diff --git a/interface/resources/icons/defaultNameCardUser.png b/interface/resources/icons/defaultNameCardUser.png new file mode 100644 index 0000000000..d0c7933db2 Binary files /dev/null and b/interface/resources/icons/defaultNameCardUser.png differ diff --git a/interface/resources/qml/controls-uit/CheckBox.qml b/interface/resources/qml/controls-uit/CheckBox.qml index 544609b478..aec579755a 100644 --- a/interface/resources/qml/controls-uit/CheckBox.qml +++ b/interface/resources/qml/controls-uit/CheckBox.qml @@ -21,9 +21,9 @@ Original.CheckBox { property int colorScheme: hifi.colorSchemes.light readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light - readonly property int boxSize: 14 + property int boxSize: 14 readonly property int boxRadius: 3 - readonly property int checkSize: 10 + readonly property int checkSize: Math.max(boxSize - 8, 10) readonly property int checkRadius: 2 style: CheckBoxStyle { @@ -32,21 +32,35 @@ Original.CheckBox { width: boxSize height: boxSize radius: boxRadius + border.width: 1 + border.color: pressed || hovered + ? hifi.colors.checkboxCheckedBorder + : (checkBox.isLightColorScheme ? hifi.colors.checkboxLightFinish : hifi.colors.checkboxDarkFinish) gradient: Gradient { GradientStop { position: 0.2 color: pressed || hovered - ? (checkBox.isLightColorScheme ? hifi.colors.checkboxDarkStart : hifi.colors.checkboxLightStart) + ? (checkBox.isLightColorScheme ? hifi.colors.checkboxChecked : hifi.colors.checkboxLightStart) : (checkBox.isLightColorScheme ? hifi.colors.checkboxLightStart : hifi.colors.checkboxDarkStart) } GradientStop { position: 1.0 color: pressed || hovered - ? (checkBox.isLightColorScheme ? hifi.colors.checkboxDarkFinish : hifi.colors.checkboxLightFinish) + ? (checkBox.isLightColorScheme ? hifi.colors.checkboxChecked : hifi.colors.checkboxLightFinish) : (checkBox.isLightColorScheme ? hifi.colors.checkboxLightFinish : hifi.colors.checkboxDarkFinish) } } + Rectangle { + visible: pressed || hovered + anchors.centerIn: parent + id: innerBox + width: checkSize - 4 + height: width + radius: checkRadius + color: hifi.colors.checkboxCheckedBorder + } + Rectangle { id: check width: checkSize @@ -54,7 +68,7 @@ Original.CheckBox { radius: checkRadius anchors.centerIn: parent color: hifi.colors.checkboxChecked - border.width: 1 + border.width: 2 border.color: hifi.colors.checkboxCheckedBorder visible: checked && !pressed || !checked && pressed } diff --git a/interface/resources/qml/controls-uit/Table.qml b/interface/resources/qml/controls-uit/Table.qml index 35029ad8bf..8e685dc253 100644 --- a/interface/resources/qml/controls-uit/Table.qml +++ b/interface/resources/qml/controls-uit/Table.qml @@ -20,6 +20,7 @@ TableView { property int colorScheme: hifi.colorSchemes.light readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light property bool expandSelectedRow: false + property bool centerHeaderText: false model: ListModel { } @@ -34,9 +35,12 @@ TableView { size: hifi.fontSizes.tableHeading font.capitalization: Font.AllUppercase color: hifi.colors.baseGrayHighlight + horizontalAlignment: (centerHeaderText ? Text.AlignHCenter : Text.AlignLeft) anchors { left: parent.left leftMargin: hifi.dimensions.tablePadding + right: parent.right + rightMargin: hifi.dimensions.tablePadding verticalCenter: parent.verticalCenter } } @@ -48,7 +52,7 @@ TableView { size: hifi.fontSizes.tableHeadingIcon anchors { left: titleText.right - leftMargin: -hifi.fontSizes.tableHeadingIcon / 3 + leftMargin: -hifi.fontSizes.tableHeadingIcon / 3 - (centerHeaderText ? 3 : 0) right: parent.right rightMargin: hifi.dimensions.tablePadding verticalCenter: titleText.verticalCenter diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index ffb42d2fff..0bc6afd241 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -9,28 +9,128 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -import Hifi 1.0 +import Hifi 1.0 as Hifi import QtQuick 2.5 +import QtGraphicalEffects 1.0 import "../styles-uit" - -Column { - property string displayName: ""; - property string userName: ""; - property int displayTextHeight: 18; - property int usernameTextHeight: 12; - - RalewaySemiBold { - text: parent.displayName; - size: parent.displayTextHeight; - elide: Text.ElideRight; - width: parent.width; +Row { + id: thisNameCard + // Spacing + spacing: 10 + // Anchors + anchors.top: parent.top + anchors { + topMargin: (parent.height - contentHeight)/2 + bottomMargin: (parent.height - contentHeight)/2 + leftMargin: 10 + rightMargin: 10 } - RalewayLight { - visible: parent.displayName; - text: parent.userName; - size: parent.usernameTextHeight; - elide: Text.ElideRight; - width: parent.width; + + // Properties + property int contentHeight: 50 + property string displayName: "" + property string userName: "" + property int displayTextHeight: 18 + property int usernameTextHeight: 12 + + Column { + id: avatarImage + // Size + height: contentHeight + width: height + Image { + id: userImage + source: "../../icons/defaultNameCardUser.png" + // Anchors + width: parent.width + height: parent.height + } + } + Column { + id: textContainer + // Size + width: parent.width - avatarImage.width - parent.anchors.leftMargin - parent.anchors.rightMargin - parent.spacing + height: contentHeight + + // DisplayName Text + FiraSansSemiBold { + id: displayNameText + // Properties + text: thisNameCard.displayName + elide: Text.ElideRight + // Size + width: parent.width + // Text Size + size: thisNameCard.displayTextHeight + // Text Positioning + verticalAlignment: Text.AlignVCenter + } + + // UserName Text + FiraSansRegular { + id: userNameText + // Properties + text: thisNameCard.userName + elide: Text.ElideRight + visible: thisNameCard.displayName + // Size + width: parent.width + // Text Size + size: thisNameCard.usernameTextHeight + // Text Positioning + verticalAlignment: Text.AlignVCenter + } + + // Spacer + Item { + height: 4 + width: parent.width + } + + // VU Meter + Rectangle { // CHANGEME to the appropriate type! + id: nameCardVUMeter + objectName: "AvatarInputs" + // Size + width: parent.width + height: 8 + // Style + radius: 4 + // Rectangle for the VU meter base + Rectangle { + id: vuMeterBase + // Anchors + anchors.fill: parent + // Style + color: "#dbdbdb" // Very appropriate hex value here + radius: parent.radius + } + // Rectangle for the VU meter audio level + Rectangle { + id: vuMeterLevel + // Size + width: (nameCardVUMeter.audioLevel) * parent.width + // Style + color: "#dbdbdb" // Very appropriate hex value here + radius: parent.radius + // Anchors + anchors.bottom: parent.bottom + anchors.top: parent.top + anchors.left: parent.left + } + // Gradient for the VU meter audio level + LinearGradient { + anchors.fill: vuMeterLevel + source: vuMeterLevel + start: Qt.point(0, 0) + end: Qt.point(parent.width, 0) + gradient: Gradient { + GradientStop { position: 0.05; color: "#00CFEF" } + GradientStop { position: 0.5; color: "#9450A5" } + GradientStop { position: 0.95; color: "#EA4C5F" } + } + } + } } } diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 7a8dc4722e..af99d9a2e1 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -28,19 +28,272 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 +import "../styles-uit" +import "../controls-uit" as HifiControls -Rectangle { - id: pal; - property int keepFromHorizontalScroll: 1; - width: parent.width - keepFromHorizontalScroll; - height: parent.height; +Item { + id: pal + // Size + width: parent.width + height: parent.height + // Properties + property int myCardHeight: 70 + property int rowHeight: 70 + property int actionButtonWidth: 75 + property int nameCardWidth: width - actionButtonWidth*(iAmAdmin ? 4 : 2) - property int nameWidth: width/2; - property int actionWidth: nameWidth / (table.columnCount - 1); - property int rowHeight: 50; - property var userData: []; - property var myData: ({displayName: "", userName: ""}); // valid dummy until set - property bool iAmAdmin: false; + // This contains the current user's NameCard and will contain other information in the future + Rectangle { + id: myInfo + // Size + width: pal.width + height: myCardHeight + // Anchors + anchors.top: pal.top + // Properties + radius: hifi.dimensions.borderRadius + // This NameCard refers to the current user's NameCard (the one above the table) + NameCard { + id: myCard + // Properties + displayName: myData.displayName + userName: myData.userName + // Size + width: nameCardWidth + height: parent.height + // Anchors + anchors.left: parent.left + } + } + // Rectangles used to cover up rounded edges on bottom of MyInfo Rectangle + Rectangle { + color: "#FFFFFF" + width: pal.width + height: 10 + anchors.top: myInfo.bottom + anchors.left: parent.left + } + Rectangle { + color: "#FFFFFF" + width: pal.width + height: 10 + anchors.bottom: table.top + anchors.left: parent.left + } + // Rectangle that houses "ADMIN" string + Rectangle { + id: adminTab + // Size + width: actionButtonWidth * 2 - 2 + height: 40 + // Anchors + anchors.bottom: myInfo.bottom + anchors.bottomMargin: -10 + anchors.right: myInfo.right + // Properties + visible: iAmAdmin + // Style + color: hifi.colors.tableRowLightEven + radius: hifi.dimensions.borderRadius + border.color: hifi.colors.lightGrayText + border.width: 2 + // "ADMIN" text + RalewaySemiBold { + text: "ADMIN" + // Text size + size: hifi.fontSizes.tableHeading + 2 + // Anchors + anchors.top: parent.top + anchors.topMargin: 8 + anchors.left: parent.left + anchors.right: parent.right + // Style + font.capitalization: Font.AllUppercase + color: hifi.colors.redHighlight + // Alignment + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignTop + } + } + // This TableView refers to the table (below the current user's NameCard) + HifiControls.Table { + id: table + // Size + height: pal.height - myInfo.height - 4 + width: pal.width - 4 + // Anchors + anchors.left: parent.left + anchors.top: myInfo.bottom + // Properties + centerHeaderText: true + sortIndicatorVisible: true + headerVisible: true + onSortIndicatorColumnChanged: sortModel() + onSortIndicatorOrderChanged: sortModel() + + TableViewColumn { + role: "displayName" + title: "NAMES" + width: nameCardWidth + movable: false + resizable: false + } + TableViewColumn { + role: "personalMute" + title: "MUTE" + width: actionButtonWidth + movable: false + resizable: false + } + TableViewColumn { + role: "ignore" + title: "IGNORE" + width: actionButtonWidth + movable: false + resizable: false + } + TableViewColumn { + visible: iAmAdmin + role: "mute" + title: "SILENCE" + width: actionButtonWidth + movable: false + resizable: false + } + TableViewColumn { + visible: iAmAdmin + role: "kick" + title: "BAN" + width: actionButtonWidth + movable: false + resizable: false + } + model: userModel + + // This Rectangle refers to each Row in the table. + rowDelegate: Rectangle { // The only way I know to specify a row height. + // Size + height: rowHeight + color: styleData.selected + ? "#afafaf" + : styleData.alternate ? hifi.colors.tableRowLightEven : hifi.colors.tableRowLightOdd + } + + // This Item refers to the contents of each Cell + itemDelegate: Item { + id: itemCell + property bool isCheckBox: typeof(styleData.value) === 'boolean' + // This NameCard refers to the cell that contains an avatar's + // DisplayName and UserName + NameCard { + id: nameCard + // Properties + displayName: styleData.value + userName: model.userName + visible: !isCheckBox + // Size + width: nameCardWidth + height: parent.height + // Anchors + anchors.left: parent.left + } + + // This CheckBox belongs in the columns that contain the action buttons ("Mute", "Ban", etc) + HifiControls.CheckBox { + visible: isCheckBox + anchors.centerIn: parent + boxSize: 24 + onClicked: { + var newValue = !model[styleData.role] + var datum = userData[model.userIndex] + datum[styleData.role] = model[styleData.role] = newValue + Users[styleData.role](model.sessionId) + // Just for now, while we cannot undo things: + userData.splice(model.userIndex, 1) + sortModel() + } + } + } + } + // Separator between user and admin functions + Rectangle { + // Size + width: 2 + height: table.height + // Anchors + anchors.left: adminTab.left + anchors.top: table.top + // Properties + visible: iAmAdmin + color: hifi.colors.lightGrayText + } + // This Rectangle refers to the [?] popup button + Rectangle { + color: hifi.colors.tableBackgroundLight + width: 20 + height: hifi.dimensions.tableHeaderHeight - 2 + anchors.left: table.left + anchors.top: table.top + anchors.topMargin: 1 + anchors.leftMargin: nameCardWidth/2 + 24 + RalewayRegular { + id: helpText + text: "[?]" + size: hifi.fontSizes.tableHeading + 2 + font.capitalization: Font.AllUppercase + color: hifi.colors.darkGray + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + anchors.fill: parent + } + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.LeftButton + hoverEnabled: true + onClicked: namesPopup.visible = true + onEntered: helpText.color = hifi.colors.baseGrayHighlight + onExited: helpText.color = hifi.colors.darkGray + } + } + // Explanitory popup upon clicking "[?]" + Item { + visible: false + id: namesPopup + anchors.fill: pal + Rectangle { + anchors.fill: parent + color: "black" + opacity: 0.5 + radius: hifi.dimensions.borderRadius + } + Rectangle { + width: Math.min(parent.width * 0.75, 400) + height: popupText.contentHeight*2 + anchors.centerIn: parent + radius: hifi.dimensions.borderRadius + color: "white" + FiraSansSemiBold { + id: popupText + text: "This is temporary text. It will eventually be used to explain what 'Names' means." + size: hifi.fontSizes.textFieldInput + color: hifi.colors.darkGray + horizontalAlignment: Text.AlignHCenter + anchors.fill: parent + wrapMode: Text.WordWrap + } + } + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.LeftButton + onClicked: { + namesPopup.visible = false + } + } + } + + property var userData: [] + property var myData: ({displayName: "", userName: ""}) // valid dummy until set + property bool iAmAdmin: false function findSessionIndex(sessionId, optionalData) { // no findIndex in .qml var i, data = optionalData || userData, length = data.length; for (var i = 0; i < length; i++) { @@ -118,7 +371,7 @@ Rectangle { datum[property] = false; } } - ['ignore', 'spacer', 'mute', 'kick'].forEach(init); + ['personalMute', 'ignore', 'mute', 'kick'].forEach(init); datum.userIndex = userIndex++; userModel.append(datum); }); @@ -135,91 +388,4 @@ Rectangle { target: table.selection onSelectionChanged: pal.noticeSelection() } - - Column { - NameCard { - id: myCard; - width: nameWidth; - displayName: myData.displayName; - userName: myData.userName; - } - TableView { - id: table; - TableViewColumn { - role: "displayName"; - title: "Name"; - width: nameWidth - } - TableViewColumn { - role: "ignore"; - title: "Ignore" - width: actionWidth - } - TableViewColumn { - title: ""; - width: actionWidth - } - TableViewColumn { - visible: iAmAdmin; - role: "mute"; - title: "Mute"; - width: actionWidth - } - TableViewColumn { - visible: iAmAdmin; - role: "kick"; - title: "Ban" - width: actionWidth - } - model: userModel; - rowDelegate: Rectangle { // The only way I know to specify a row height. - height: rowHeight; - // The rest of this is cargo-culted to restore the default styling - SystemPalette { - id: myPalette; - colorGroup: SystemPalette.Active - } - color: { - var baseColor = styleData.alternate?myPalette.alternateBase:myPalette.base - return styleData.selected?myPalette.highlight:baseColor - } - } - itemDelegate: Item { - id: itemCell; - property bool isCheckBox: typeof(styleData.value) === 'boolean'; - NameCard { - id: nameCard; - visible: !isCheckBox; - width: nameWidth; - displayName: styleData.value; - userName: model.userName; - } - Rectangle { - radius: itemCell.height / 4; - visible: isCheckBox; - color: styleData.value ? "green" : "red"; - anchors.fill: parent; - MouseArea { - anchors.fill: parent; - acceptedButtons: Qt.LeftButton; - hoverEnabled: true; - onClicked: { - var newValue = !model[styleData.role]; - var datum = userData[model.userIndex]; - datum[styleData.role] = model[styleData.role] = newValue; - Users[styleData.role](model.sessionId); - // Just for now, while we cannot undo things: - userData.splice(model.userIndex, 1); - sortModel(); - } - } - } - } - height: pal.height - myCard.height; - width: pal.width; - sortIndicatorVisible: true; - onSortIndicatorColumnChanged: sortModel(); - onSortIndicatorOrderChanged: sortModel(); - } - } } diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index f2698da574..da1b2868a7 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -89,8 +89,8 @@ Item { readonly property color transparent: "#00ffffff" // Control specific colors - readonly property color tableRowLightOdd: "#eaeaea" // Equivalent to white50 over #e3e3e3 background - readonly property color tableRowLightEven: "#c6c6c6" // Equivavlent to "#1a575757" over #e3e3e3 background + readonly property color tableRowLightOdd: "#fafafa" + readonly property color tableRowLightEven: "#eeeeee" // Equivavlent to "#1a575757" over #e3e3e3 background readonly property color tableRowDarkOdd: "#2e2e2e" // Equivalent to "#80393939" over #404040 background readonly property color tableRowDarkEven: "#1c1c1c" // Equivalent to "#a6181818" over #404040 background readonly property color tableBackgroundLight: tableRowLightEven diff --git a/scripts/system/pal.js b/scripts/system/pal.js index c426f3fd87..9d419e5a0f 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -79,7 +79,7 @@ ExtendedOverlay.applyPickRay = function (pickRay, cb) { // cb(overlay) on the on var pal = new OverlayWindow({ title: 'People Action List', source: 'hifi/Pal.qml', - width: 480, + width: 580, height: 640, visible: false }); @@ -140,12 +140,13 @@ function populateUserList() { function usernameFromIDReply(id, username, machineFingerprint) { var data; // If the ID we've received is our ID... - if (AvatarList.getAvatar('').sessionUUID === id) { + if (MyAvatar.sessionUUID === id) { // Set the data to contain specific strings. - data = ['', username + ' (hidden)'] + data = ['', username] } else { - // Set the data to contain the ID and the username+ID concat string. - data = [id, username + '/' + machineFingerprint]; + // Set the data to contain the ID and the username (if we have one) + // or fingerprint (if we don't have a username) string. + data = [id, username || machineFingerprint]; } print('Username Data:', JSON.stringify(data)); // Ship the data off to QML