diff --git a/interface/resources/icons/warning-svgrepo-com.svg b/interface/resources/icons/warning-svgrepo-com.svg new file mode 100644 index 00000000000..f4c72dccbbe --- /dev/null +++ b/interface/resources/icons/warning-svgrepo-com.svg @@ -0,0 +1 @@ +warning \ No newline at end of file diff --git a/interface/resources/qml/controlsUit/CheckBox.qml b/interface/resources/qml/controlsUit/CheckBox.qml index abf08908fbc..57a6ac08b0d 100644 --- a/interface/resources/qml/controlsUit/CheckBox.qml +++ b/interface/resources/qml/controlsUit/CheckBox.qml @@ -10,6 +10,7 @@ import QtQuick 2.2 import QtQuick.Controls 2.2 as Original +import QtGraphicalEffects 1.0 import "../stylesUit" @@ -30,6 +31,8 @@ Original.CheckBox { property string labelFontFamily: "Raleway" property int labelFontSize: 14; property int labelFontWeight: Font.DemiBold; + property bool isFeatureDisabled: false + property string featureDisabledToolTip; focusPolicy: Qt.ClickFocus hoverEnabled: true @@ -43,65 +46,94 @@ Original.CheckBox { } } + indicator: Item { + width: isFeatureDisabled ? featureDisabledWarning.width : box.width + anchors.left: parent.left - indicator: Rectangle { - id: box - implicitWidth: boxSize - implicitHeight: boxSize - radius: boxRadius - y: parent.height / 2 - height / 2 - 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.checkboxChecked : hifi.colors.checkboxLightStart) - : (checkBox.isLightColorScheme ? hifi.colors.checkboxLightStart : hifi.colors.checkboxDarkStart) - } - GradientStop { - position: 1.0 - color: pressed || hovered - ? (checkBox.isLightColorScheme ? hifi.colors.checkboxChecked : hifi.colors.checkboxLightFinish) - : (checkBox.isLightColorScheme ? hifi.colors.checkboxLightFinish : hifi.colors.checkboxDarkFinish) - } - } + Image { + id: featureDisabledWarning + visible: isFeatureDisabled + source: "/icons/warning-svgrepo-com.svg" - Rectangle { - visible: pressed || hovered - anchors.centerIn: parent - id: innerBox - width: checkSize - 4 - height: width - radius: checkRadius - color: hifi.colors.checkboxCheckedBorder - } + anchors.bottom: box.top + anchors.left: parent.left + anchors.bottomMargin: 3 + height: isFeatureDisabled ? checkBox.height / 2.5 : 0 + width: height - Rectangle { - id: check - width: checkSize - height: checkSize - radius: checkRadius - anchors.centerIn: parent - color: isRedCheck ? hifi.colors.checkboxCheckedRed : hifi.colors.checkboxChecked - border.width: 2 - border.color: isRedCheck? hifi.colors.checkboxCheckedBorderRed : hifi.colors.checkboxCheckedBorder - visible: checked && !pressed || !checked && pressed + ToolTip { + id: toolTip + toolTip: checkBox.featureDisabledToolTip + clip: false // Doesn't seem useful. + } + + ColorOverlay { + anchors.fill: parent + source: parent + color: "red" + } } Rectangle { - id: disabledOverlay - visible: !enabled - width: boxSize - height: boxSize + id: box + implicitWidth: boxSize + implicitHeight: boxSize + anchors.leftMargin: featureDisabledWarning.width / 2 radius: boxRadius + y: checkBox.height / 2 - height / 2 border.width: 1 - border.color: hifi.colors.baseGrayHighlight - color: hifi.colors.baseGrayHighlight - opacity: 0.5 + 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.checkboxChecked : hifi.colors.checkboxLightStart) + : (checkBox.isLightColorScheme ? hifi.colors.checkboxLightStart : hifi.colors.checkboxDarkStart) + } + GradientStop { + position: 1.0 + color: pressed || hovered + ? (checkBox.isLightColorScheme ? hifi.colors.checkboxChecked : hifi.colors.checkboxLightFinish) + : (checkBox.isLightColorScheme ? hifi.colors.checkboxLightFinish : hifi.colors.checkboxDarkFinish) + } + } + + Rectangle { + id: innerBox + width: checkSize - 4 + height: width + radius: checkRadius + anchors.centerIn: parent + color: hifi.colors.checkboxCheckedBorder + visible: pressed || hovered + } + + Rectangle { + id: check + width: checkSize + height: checkSize + radius: checkRadius + anchors.centerIn: parent + color: isRedCheck ? hifi.colors.checkboxCheckedRed : hifi.colors.checkboxChecked + border.width: 2 + border.color: isRedCheck? hifi.colors.checkboxCheckedBorderRed : hifi.colors.checkboxCheckedBorder + visible: checked && !pressed || !checked && pressed + } + + Rectangle { + id: disabledOverlay + visible: !enabled + width: boxSize + height: boxSize + radius: boxRadius + border.width: 1 + border.color: hifi.colors.baseGrayHighlight + color: hifi.colors.baseGrayHighlight + opacity: 0.5 + } } } diff --git a/interface/resources/qml/controlsUit/ToolTip.qml b/interface/resources/qml/controlsUit/ToolTip.qml index 4fe36adcd5c..4d33ba4c756 100644 --- a/interface/resources/qml/controlsUit/ToolTip.qml +++ b/interface/resources/qml/controlsUit/ToolTip.qml @@ -7,10 +7,12 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +// But practically identical to this: import QtQuick 2.5 Item { + anchors.fill: parent property string toolTip property bool showToolTip: false @@ -20,7 +22,8 @@ Item { width: toolTipText.width + 4 height: toolTipText.height + 4 - opacity: (toolTip != "" && showToolTip) ? 1 : 0 + opacity: (toolTip != "" && showToolTip) ? 1 : 0 // Doesn't work. + //opacity: 1 // Works. color: "#ffffaa" border.color: "#0a0a0a" Text { @@ -42,10 +45,14 @@ Item { onEntered: showTimer.start() onExited: { showToolTip = false; showTimer.stop(); } hoverEnabled: true + + onClicked: { + showToolTip = true; + } } Timer { id: showTimer interval: 250 onTriggered: { showToolTip = true; } } -} \ No newline at end of file +} diff --git a/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml b/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml index b3a9fe3ba92..9b55e2398d0 100644 --- a/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml +++ b/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml @@ -18,10 +18,13 @@ Preference { height: spacer.height + Math.max(hifi.dimensions.controlLineHeight, checkBox.implicitHeight) property bool value: false Component.onCompleted: { + //checkBox.enabled = preference.enabled; checkBox.checked = preference.value; + checkBox.isFeatureDisabled = preference.functionalityDisabledTooltip; + checkBox.featureDisabledToolTip = preference.tooltip; value = checkBox.checked; preference.value = Qt.binding(function(){ return checkBox.checked; }); - value = checkBox.checked; + value = checkBox.checked; // Why is this here twice? } function save() { diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 72504c5571f..804c61f412b 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -633,12 +633,18 @@ Menu::Menu() { true, &UserActivityLogger::getInstance(), SLOT(disable(bool))); - addCheckableActionToQMenuAndActionHash(networkMenu, - MenuOption::DisableCrashLogger, - 0, - true, - &UserActivityLogger::getInstance(), - SLOT(crashMonitorDisable(bool))); + { + auto ual = &UserActivityLogger::getInstance(); + addCheckableActionToQMenuAndActionHash(networkMenu, + MenuOption::GenerateAndSubmitCrashReports, + 0, + true, + ual, + SLOT(crashMonitorDisable(bool)), + UNSPECIFIED_POSITION, + QString(), + ual->isCrashMonitorEnabled()); + } addActionToQMenuAndActionHash(networkMenu, MenuOption::ShowDSConnectTable, 0, qApp, SLOT(loadDomainConnectionDialog())); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index c42345894ca..e3b89c8fa80 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -90,7 +90,6 @@ namespace MenuOption { const QString DeleteAvatarEntitiesBookmark = "Delete Avatar Entities Bookmark"; const QString DeleteBookmark = "Delete Bookmark..."; const QString DisableActivityLogger = "Disable Activity Logger"; - const QString DisableCrashLogger = "Disable Crash Reporter"; const QString DisableEyelidAdjustment = "Disable Eyelid Adjustment"; const QString DisableLightEntities = "Disable Light Entities"; const QString DisplayCrashOptions = "Display Crash Options"; @@ -123,6 +122,7 @@ namespace MenuOption { const QString FixGaze = "Fix Gaze (no saccade)"; const QString Forward = "Forward"; const QString FrameTimer = "Show Timer"; + const QString GenerateAndSubmitCrashReports = "Generate and Submit Crash Reports"; const QString Help = "Help..."; const QString HomeLocation = "Home "; const QString IncreaseAvatarSize = "Increase Avatar Size"; diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 4e338a629b1..d7dfb91bab2 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -220,11 +220,13 @@ int main(int argc, const char* argv[]) { } qDebug() << "UserActivityLogger is enabled:" << ual.isEnabled(); - bool isCrashHandlerEnabled = ual.isCrashMonitorEnabled() || parser.isSet(forceCrashReportingOption); - qDebug() << "Crash handler logger is enabled:" << isCrashHandlerEnabled; - if (isCrashHandlerEnabled) { - auto crashHandlerStarted = startCrashHandler(argv[0]); - qDebug() << "Crash handler started:" << crashHandlerStarted; + { + bool isCrashHandlerEnabled = ual.isCrashMonitorEnabled() || parser.isSet(forceCrashReportingOption); + qDebug() << "Crash handler logger is enabled:" << isCrashHandlerEnabled; + if (isCrashHandlerEnabled) { + auto crashHandlerStarted = startCrashHandler(argv[0]); + qDebug() << "Crash handler started:" << crashHandlerStarted; + } } const QString& applicationName = getInterfaceSharedMemoryName(); diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 9c1c4fa7847..16286f620b2 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -257,11 +257,15 @@ void setupPreferences() { } { - auto getter = []()->bool { return !Menu::getInstance()->isOptionChecked(MenuOption::DisableCrashLogger); }; - auto setter = [](bool value) { Menu::getInstance()->setIsOptionChecked(MenuOption::DisableCrashLogger, !value); }; - preferences->addPreference(new CheckPreference("Privacy", "Send crashes - Vircadia uses information provided by your " - "client to improve the product through crash reports. By allowing Vircadia to collect " - "this information you are helping to improve the product. ", getter, setter)); + auto getter = []()->bool { return Menu::getInstance()->isOptionChecked(MenuOption::GenerateAndSubmitCrashReports); }; + auto setter = [](bool value) { Menu::getInstance()->setIsOptionChecked(MenuOption::GenerateAndSubmitCrashReports, !value); }; + auto preference = new CheckPreference("Privacy", "Send crashes - Vircadia can use information provided by your " + "client to improve the product through crash reports. By allowing developers to collect " + "this information you are helping to improve the product. ", getter, setter); + if (!UserActivityLogger::getInstance().isCrashMonitorEnabled()) { + preference->setFunctionalityDisabledTooltip("Your version of the application was not built with support for crash reporting."); + } + preferences->addPreference(preference); } static const QString AVATAR_TUNING { "Avatar Tuning" }; diff --git a/libraries/networking/src/UserActivityLogger.h b/libraries/networking/src/UserActivityLogger.h index 39efee03c40..9d66d159746 100644 --- a/libraries/networking/src/UserActivityLogger.h +++ b/libraries/networking/src/UserActivityLogger.h @@ -36,7 +36,7 @@ public slots: bool isDisabledSettingSet() const { return _disabled.isSet(); } bool isCrashMonitorEnabled() { return !_crashMonitorDisabled.get(); } - bool isCrashMonitorDisabledSettingSet() const { return _crashMonitorDisabled.isSet(); } + bool isCrashMonitorDisabledSettingSet() const { return _crashMonitorDisabled.isSet(); } // Is this actually used? void disable(bool disable); void crashMonitorDisable(bool disable); diff --git a/libraries/shared/src/Preferences.h b/libraries/shared/src/Preferences.h index a195dc457ff..fbf20cb01bc 100644 --- a/libraries/shared/src/Preferences.h +++ b/libraries/shared/src/Preferences.h @@ -382,7 +382,9 @@ class AvatarPreference : public BrowsePreference { class CheckPreference : public BoolPreference { Q_OBJECT + //Q_PROPERTY(bool enabled READ getEnabled CONSTANT) Q_PROPERTY(bool indented READ getIndented CONSTANT) + Q_PROPERTY(QString functionalityDisabledTooltip READ getFunctionalityDisabledTooltip CONSTANT) public: using Getter = std::function; using Setter = std::function; @@ -391,10 +393,21 @@ class CheckPreference : public BoolPreference { : BoolPreference(category, name, getter, setter) { } Type getType() override { return Checkbox; } + //bool getEnabled() { return _isEnabled; } + //void setEnabled(const bool enabled) { _isEnabled = enabled; } + bool getIndented() { return _isIndented; } void setIndented(const bool indented) { _isIndented = indented; } + + //const QString& getTooltip() { return _tooltip; } + //void setTooltip(const QString tooltip) { _tooltip = tooltip; } + + const QString& getFunctionalityDisabledTooltip() { return _functionalityDisabledTooltip; } + void setFunctionalityDisabledTooltip(const QString functionalityDisabledTooltip) { _functionalityDisabledTooltip = functionalityDisabledTooltip; } protected: + //bool _isEnabled { true }; bool _isIndented { false }; + QString _functionalityDisabledTooltip; }; class PrimaryHandPreference : public StringPreference { diff --git a/libraries/ui/src/ui/Menu.cpp b/libraries/ui/src/ui/Menu.cpp index 00de4c6ce83..f2ee8483131 100644 --- a/libraries/ui/src/ui/Menu.cpp +++ b/libraries/ui/src/ui/Menu.cpp @@ -208,12 +208,14 @@ QAction* Menu::addCheckableActionToQMenuAndActionHash(MenuWrapper* destinationMe const QObject* receiver, const char* member, int menuItemLocation, - const QString& grouping) { + const QString& grouping, + const bool functionalityEnabled) { QAction* action = addActionToQMenuAndActionHash(destinationMenu, actionName, shortcut, receiver, member, QAction::NoRole, menuItemLocation); action->setCheckable(true); action->setChecked(checked); + action->setDisabled(!functionalityEnabled); if (isValidGrouping(grouping)) { _groupingActions[grouping] << action; @@ -229,7 +231,8 @@ QAction* Menu::addCheckableActionToQMenuAndActionHash(MenuWrapper* destinationMe const QKeySequence& shortcut, const bool checked, int menuItemLocation, - const QString& grouping) { + const QString& grouping) { + auto action = addCheckableActionToQMenuAndActionHash(destinationMenu, actionName, shortcut, checked, nullptr, nullptr, menuItemLocation, grouping); connect(action, &QAction::triggered, handler); return action; diff --git a/libraries/ui/src/ui/Menu.h b/libraries/ui/src/ui/Menu.h index 63d307301d5..6c5c8597a67 100644 --- a/libraries/ui/src/ui/Menu.h +++ b/libraries/ui/src/ui/Menu.h @@ -93,7 +93,8 @@ class Menu : public QMenuBar { const QObject* receiver = NULL, const char* member = NULL, int menuItemLocation = UNSPECIFIED_POSITION, - const QString& grouping = QString()); + const QString& grouping = QString(), + const bool functionalityEnabled = true); QAction* addCheckableActionToQMenuAndActionHash(MenuWrapper* destinationMenu, const QString& actionName,