diff --git a/interface/interface_en.ts b/interface/interface_en.ts new file mode 100644 index 0000000000..48b395339e --- /dev/null +++ b/interface/interface_en.ts @@ -0,0 +1,274 @@ + + + + + Application + + + Export Voxels + + + + + Sparse Voxel Octree Files (*.svo) + + + + + Open Script + + + + + JavaScript Files (*.js) + + + + + ChatWindow + + + + Chat + + + + + + Connecting to XMPP... + + + + + + online now: + + + + + day + + %n day + %n days + + + + + hour + + %n hour + %n hours + + + + + minute + + %n minute + %n minutes + + + + second + + %n second + %n seconds + + + + + %1 online now: + + + + + Dialog + + + + + + Update Required + + + + + + Download + + + + + + Skip Version + + + + + + Close + + + + + Menu + + + Open .ini config file + + + + + + Text files (*.ini) + + + + + Save .ini config file + + + + + PreferencesDialog + + + + Cancel + + + + + + Save all changes + + + + + + + + Avatar + + + + + + <html><head/><body><p>Avatar display name <span style=" color:#909090;">(optional)</span></p></body></html> + + + + + + Not showing a name + + + + + + Head + + + + + + Body + + + + + + Advanced Tuning + + + + + + It's not recomended that you play with these settings unless you've looked into exactly what they do. + + + + + + Vertical field of view + + + + + + Lean scale (applies to Faceshift users) + + + + + + Avatar scale <span style=" color:#909090;">(default is 1.0)</span> + + + + + + Pupil dillation + + + + + + Audio Jitter Buffer Samples (0 for automatic) + + + + + + Faceshift eye detection + + + + + + Voxels + + + + + + Maximum voxels + + + + + + Max voxels sent each second + + + + + QObject + + + + Import Voxels + + + + + Loading ... + + + + + Place voxels + + + + + <b>Import</b> %1 as voxels + + + + + Cancel + + + + diff --git a/interface/resources/resources.qrc b/interface/resources/resources.qrc index 35c0e40270..0dc5a27651 100644 --- a/interface/resources/resources.qrc +++ b/interface/resources/resources.qrc @@ -1,5 +1,6 @@ - + + styles/search.svg images/close.svg images/kill-script.svg images/reload.svg diff --git a/interface/resources/styles/avatar.svg b/interface/resources/styles/avatar.svg new file mode 100644 index 0000000000..f9382edee4 --- /dev/null +++ b/interface/resources/styles/avatar.svg @@ -0,0 +1,27 @@ + + + + + + + + diff --git a/interface/resources/styles/close.svg b/interface/resources/styles/close.svg new file mode 100644 index 0000000000..8fe4bf4bdb --- /dev/null +++ b/interface/resources/styles/close.svg @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/interface/resources/styles/down.svg b/interface/resources/styles/down.svg new file mode 100644 index 0000000000..983ccd9597 --- /dev/null +++ b/interface/resources/styles/down.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/interface/resources/styles/global.qss b/interface/resources/styles/global.qss new file mode 100644 index 0000000000..2554f3b2c9 --- /dev/null +++ b/interface/resources/styles/global.qss @@ -0,0 +1,113 @@ +* { + padding: 0; + margin: 0; +} + +FramelessDialog { + font-family: Helvetica, Arial, sans-serif; + font-size: 16px; +} + +QLineEdit { + background-color: rgba(255, 255, 255, 1); + border-style: solid; + border-width: 1px; + border-color: #ccc; + padding: 8px; + font-size: 16px; + color: rgb(51, 51, 51); +} + +QLabel p { + color: #0e7077; + font-size: 23px; +} + +QPushButton { + border-width: 0; + border-radius: 9px; + font-family: Arial; + font-size: 18px; + color: #ffffff; + padding: 10px 0px; +} + +QSpinBox, QDoubleSpinBox { + padding: 5px; + border-width: 1; + font-size: 16px; + color: rgb(51, 51, 51); +} + +QDoubleSpinBox::up-arrow, +QSpinBox::up-arrow { + background-image: url(styles/up.svg); + background-repeat: no-repeat; + background-position: center center; +} + +QDoubleSpinBox::down-arrow, +QSpinBox::down-arrow { + background-image: url(styles/down.svg); + background-repeat: no-repeat; + background-position: center center; +} + +QDoubleSpinBox::up-button, +QSpinBox::up-button, +QDoubleSpinBox::down-button, +QSpinBox::down-button { + width: 26px; + height: 13px; + + background-color: #f2f2f2; + border-color: #ccc; + border-style: solid; + border-width: 1px; +} + +QDoubleSpinBox::up-button, +QSpinBox::up-button { + + margin-top:2px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; +} + +QDoubleSpinBox::down-button, +QSpinBox::down-button { + margin-bottom:3px; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; +} + +QSlider { + width: 125px; + height: 18px; +} + +QSlider::groove:horizontal { + border: none; + background-image: url(styles/slider-bg.svg); + background-repeat: no-repeat; + background-position: center center; +} + +QSlider::handle:horizontal { + width: 18px; + height: 18px; + background-image: url(styles/slider-handle.svg); + background-repeat: no-repeat; + background-position: center center; +} + +QPushButton#closeButton { + border-color: #ccc; + border-style: solid; + border-width: 1px; + border-radius: 0; + background-color: #fff; + background-image: url(styles/close.svg); + background-repeat: no-repeat; + background-position: center center; +} diff --git a/interface/resources/styles/preferences.qss b/interface/resources/styles/preferences.qss new file mode 100644 index 0000000000..643fd13a77 --- /dev/null +++ b/interface/resources/styles/preferences.qss @@ -0,0 +1,21 @@ +QLabel#avatarLabel { + background-image: url(styles/avatar.svg); + background-repeat: no-repeat; + background-position: left center; +} + +QLabel#advancedTuningLabel { + background-image: url(styles/wrench.svg); + background-repeat: no-repeat; + background-position: left center; +} + +QPushButton#buttonBrowseHead, +QPushButton#buttonBrowseBody { + background-image: url(styles/search.svg); + background-repeat: no-repeat; + background-position: center center; + background-color: #fff; + border-radius: 0; + padding: 0; +} diff --git a/interface/resources/styles/slider-bg.svg b/interface/resources/styles/slider-bg.svg new file mode 100644 index 0000000000..36c6478026 --- /dev/null +++ b/interface/resources/styles/slider-bg.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/interface/resources/styles/slider-handle.svg b/interface/resources/styles/slider-handle.svg new file mode 100644 index 0000000000..5d87e8599c --- /dev/null +++ b/interface/resources/styles/slider-handle.svg @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/interface/resources/styles/up.svg b/interface/resources/styles/up.svg new file mode 100644 index 0000000000..d122c4801e --- /dev/null +++ b/interface/resources/styles/up.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/interface/resources/styles/wrench.svg b/interface/resources/styles/wrench.svg new file mode 100644 index 0000000000..5019f92b18 --- /dev/null +++ b/interface/resources/styles/wrench.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 80007da485..c68afdbf5f 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -86,7 +86,8 @@ Menu::Menu() : _lastAvatarDetailDrop(usecTimestampNow()), _fpsAverage(FIVE_SECONDS_OF_FRAMES), _fastFPSAverage(ONE_SECOND_OF_FRAMES), - _loginAction(NULL) + _loginAction(NULL), + _preferencesDialog(NULL) { Application *appInstance = Application::getInstance(); @@ -771,164 +772,12 @@ void Menu::loginForCurrentDomain() { } void Menu::editPreferences() { - Application* applicationInstance = Application::getInstance(); - ModelsBrowser headBrowser(Head); - ModelsBrowser skeletonBrowser(Skeleton); - - const QString BROWSE_BUTTON_TEXT = "Browse"; - - QDialog dialog(applicationInstance->getWindow()); - dialog.setWindowTitle("Interface Preferences"); - - QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom); - dialog.setLayout(layout); - - QFormLayout* form = new QFormLayout(); - layout->addLayout(form, 1); - - - QHBoxLayout headModelLayout; - QString faceURLString = applicationInstance->getAvatar()->getHead()->getFaceModel().getURL().toString(); - QLineEdit headURLEdit(faceURLString); - QPushButton headBrowseButton(BROWSE_BUTTON_TEXT); - connect(&headBrowseButton, SIGNAL(clicked()), &headBrowser, SLOT(browse())); - connect(&headBrowser, SIGNAL(selected(QString)), &headURLEdit, SLOT(setText(QString))); - headURLEdit.setMinimumWidth(QLINE_MINIMUM_WIDTH); - headURLEdit.setPlaceholderText(DEFAULT_HEAD_MODEL_URL.toString()); - headModelLayout.addWidget(&headURLEdit); - headModelLayout.addWidget(&headBrowseButton); - form->addRow("Head URL:", &headModelLayout); - - QHBoxLayout skeletonModelLayout; - QString skeletonURLString = applicationInstance->getAvatar()->getSkeletonModel().getURL().toString(); - QLineEdit skeletonURLEdit(skeletonURLString); - QPushButton SkeletonBrowseButton(BROWSE_BUTTON_TEXT); - connect(&SkeletonBrowseButton, SIGNAL(clicked()), &skeletonBrowser, SLOT(browse())); - connect(&skeletonBrowser, SIGNAL(selected(QString)), &skeletonURLEdit, SLOT(setText(QString))); - skeletonURLEdit.setMinimumWidth(QLINE_MINIMUM_WIDTH); - skeletonURLEdit.setPlaceholderText(DEFAULT_BODY_MODEL_URL.toString()); - skeletonModelLayout.addWidget(&skeletonURLEdit); - skeletonModelLayout.addWidget(&SkeletonBrowseButton); - form->addRow("Skeleton URL:", &skeletonModelLayout); - - - QString displayNameString = applicationInstance->getAvatar()->getDisplayName(); - QLineEdit* displayNameEdit = new QLineEdit(displayNameString); - displayNameEdit->setMinimumWidth(QLINE_MINIMUM_WIDTH); - form->addRow("Display name:", displayNameEdit); - - QSlider* pupilDilation = new QSlider(Qt::Horizontal); - pupilDilation->setValue(applicationInstance->getAvatar()->getHead()->getPupilDilation() * pupilDilation->maximum()); - form->addRow("Pupil Dilation:", pupilDilation); - - QSlider* faceshiftEyeDeflection = new QSlider(Qt::Horizontal); - faceshiftEyeDeflection->setValue(_faceshiftEyeDeflection * faceshiftEyeDeflection->maximum()); - form->addRow("Faceshift Eye Deflection:", faceshiftEyeDeflection); - - QSpinBox* fieldOfView = new QSpinBox(); - fieldOfView->setMaximum(180.f); - fieldOfView->setMinimum(1.f); - fieldOfView->setValue(_fieldOfView); - form->addRow("Vertical Field of View (Degrees):", fieldOfView); - - QDoubleSpinBox* leanScale = new QDoubleSpinBox(); - leanScale->setValue(applicationInstance->getAvatar()->getLeanScale()); - form->addRow("Lean Scale:", leanScale); - - QDoubleSpinBox* avatarScale = new QDoubleSpinBox(); - avatarScale->setValue(applicationInstance->getAvatar()->getScale()); - form->addRow("Avatar Scale:", avatarScale); - - QSpinBox* audioJitterBufferSamples = new QSpinBox(); - audioJitterBufferSamples->setMaximum(10000); - audioJitterBufferSamples->setMinimum(-10000); - audioJitterBufferSamples->setValue(_audioJitterBufferSamples); - form->addRow("Audio Jitter Buffer Samples (0 for automatic):", audioJitterBufferSamples); - - QSpinBox* maxVoxels = new QSpinBox(); - const int MAX_MAX_VOXELS = 5000000; - const int MIN_MAX_VOXELS = 0; - const int STEP_MAX_VOXELS = 50000; - maxVoxels->setMaximum(MAX_MAX_VOXELS); - maxVoxels->setMinimum(MIN_MAX_VOXELS); - maxVoxels->setSingleStep(STEP_MAX_VOXELS); - maxVoxels->setValue(_maxVoxels); - form->addRow("Maximum Voxels:", maxVoxels); - - QSpinBox* maxVoxelsPPS = new QSpinBox(); - const int MAX_MAX_VOXELS_PPS = 6000; - const int MIN_MAX_VOXELS_PPS = 60; - const int STEP_MAX_VOXELS_PPS = 10; - maxVoxelsPPS->setMaximum(MAX_MAX_VOXELS_PPS); - maxVoxelsPPS->setMinimum(MIN_MAX_VOXELS_PPS); - maxVoxelsPPS->setSingleStep(STEP_MAX_VOXELS_PPS); - maxVoxelsPPS->setValue(_maxVoxelPacketsPerSecond); - form->addRow("Maximum Voxels Packets Per Second:", maxVoxelsPPS); - - QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - dialog.connect(buttons, SIGNAL(accepted()), SLOT(accept())); - dialog.connect(buttons, SIGNAL(rejected()), SLOT(reject())); - layout->addWidget(buttons); - - int ret = dialog.exec(); - if (ret == QDialog::Accepted) { - bool shouldDispatchIdentityPacket = false; - - if (headURLEdit.text() != faceURLString) { - // change the faceModelURL in the profile, it will also update this user's BlendFace - if (headURLEdit.text().isEmpty()) { - applicationInstance->getAvatar()->setFaceModelURL(QUrl(headURLEdit.placeholderText())); - } else { - applicationInstance->getAvatar()->setFaceModelURL(QUrl(headURLEdit.text())); - } - shouldDispatchIdentityPacket = true; - } - - if (skeletonURLEdit.text() != skeletonURLString) { - // change the skeletonModelURL in the profile, it will also update this user's Body - if (skeletonURLEdit.text().isEmpty()) { - applicationInstance->getAvatar()->setSkeletonModelURL(QUrl(skeletonURLEdit.placeholderText())); - } else { - applicationInstance->getAvatar()->setSkeletonModelURL(QUrl(skeletonURLEdit.text())); - } - shouldDispatchIdentityPacket = true; - } - - QString displayNameStr(displayNameEdit->text()); - - if (displayNameStr != displayNameString) { - applicationInstance->getAvatar()->setDisplayName(displayNameStr); - shouldDispatchIdentityPacket = true; - } - - if (shouldDispatchIdentityPacket) { - applicationInstance->getAvatar()->sendIdentityPacket(); - } - - applicationInstance->getAvatar()->getHead()->setPupilDilation(pupilDilation->value() / (float)pupilDilation->maximum()); - - _maxVoxels = maxVoxels->value(); - applicationInstance->getVoxels()->setMaxVoxels(_maxVoxels); - - _maxVoxelPacketsPerSecond = maxVoxelsPPS->value(); - - applicationInstance->getAvatar()->setLeanScale(leanScale->value()); - applicationInstance->getAvatar()->setClampedTargetScale(avatarScale->value()); - - _audioJitterBufferSamples = audioJitterBufferSamples->value(); - - if (_audioJitterBufferSamples != 0) { - applicationInstance->getAudio()->setJitterBufferSamples(_audioJitterBufferSamples); - } - - _fieldOfView = fieldOfView->value(); - applicationInstance->resizeGL(applicationInstance->getGLWidget()->width(), applicationInstance->getGLWidget()->height()); - - _faceshiftEyeDeflection = faceshiftEyeDeflection->value() / (float)faceshiftEyeDeflection->maximum(); + if (!_preferencesDialog) { + _preferencesDialog = new PreferencesDialog(Application::getInstance()->getWindow()); + _preferencesDialog->show(); + } else { + _preferencesDialog->close(); } - QMetaObject::invokeMethod(applicationInstance->getAudio(), "reset", Qt::QueuedConnection); - - sendFakeEnterEvent(); } void Menu::goToDomain(const QString newDomain) { diff --git a/interface/src/Menu.h b/interface/src/Menu.h index fb71efa5e5..e827e43014 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -22,6 +22,7 @@ #include #include "location/LocationManager.h" +#include "ui/PreferencesDialog.h" #include "ui/ChatWindow.h" const float ADJUST_LOD_DOWN_FPS = 40.0; @@ -71,10 +72,13 @@ public: void triggerOption(const QString& menuOption); QAction* getActionForOption(const QString& menuOption); - + float getAudioJitterBufferSamples() const { return _audioJitterBufferSamples; } + void setAudioJitterBufferSamples(float audioJitterBufferSamples) { _audioJitterBufferSamples = audioJitterBufferSamples; } float getFieldOfView() const { return _fieldOfView; } + void setFieldOfView(float fieldOfView) { _fieldOfView = fieldOfView; } float getFaceshiftEyeDeflection() const { return _faceshiftEyeDeflection; } + void setFaceshiftEyeDeflection(float faceshiftEyeDeflection) { _faceshiftEyeDeflection = faceshiftEyeDeflection; } BandwidthDialog* getBandwidthDialog() const { return _bandwidthDialog; } FrustumDrawMode getFrustumDrawMode() const { return _frustumDrawMode; } ViewFrustumOffset getViewFrustumOffset() const { return _viewFrustumOffset; } @@ -97,6 +101,7 @@ public: // User Tweakable PPS from Voxel Server int getMaxVoxelPacketsPerSecond() const { return _maxVoxelPacketsPerSecond; } + void setMaxVoxelPacketsPerSecond(int maxVoxelPacketsPerSecond) { _maxVoxelPacketsPerSecond = maxVoxelPacketsPerSecond; } QAction* addActionToQMenuAndActionHash(QMenu* destinationMenu, const QString& actionName, @@ -222,6 +227,7 @@ private: SimpleMovingAverage _fpsAverage; SimpleMovingAverage _fastFPSAverage; QAction* _loginAction; + QPointer _preferencesDialog; QAction* _chatAction; }; diff --git a/interface/src/ui/FramelessDialog.cpp b/interface/src/ui/FramelessDialog.cpp new file mode 100644 index 0000000000..18e3bca89a --- /dev/null +++ b/interface/src/ui/FramelessDialog.cpp @@ -0,0 +1,100 @@ +// +// FramelessDialog.cpp +// interface/src/ui +// +// Created by Stojce Slavkovski on 2/20/14. +// Copyright 2014 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 +// + +#include "Application.h" +#include "FramelessDialog.h" + +const int RESIZE_HANDLE_WIDTH = 7; + +FramelessDialog::FramelessDialog(QWidget *parent, Qt::WindowFlags flags) : +QDialog(parent, flags | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint) { + setAttribute(Qt::WA_DeleteOnClose); + + // handle rezize and move events + parentWidget()->installEventFilter(this); + + // handle minimize, restore and focus events + Application::getInstance()->installEventFilter(this); +} + +bool FramelessDialog::eventFilter(QObject* sender, QEvent* event) { + switch (event->type()) { + case QEvent::Move: + if (sender == parentWidget()) { + // move to upper left corner on app move + move(parentWidget()->geometry().topLeft()); + } + break; + case QEvent::Resize: + if (sender == parentWidget()) { + // keep full app height on resizing the app + setFixedHeight(parentWidget()->size().height()); + } + break; + case QEvent::WindowStateChange: + if (parentWidget()->isMinimized()) { + setHidden(true); + } else { + setHidden(false); + } + break; + case QEvent::ApplicationDeactivate: + // hide on minimize and focus lost + setHidden(true); + break; + case QEvent::ApplicationActivate: + setHidden(false); + break; + default: + break; + } + + return false; +} + +void FramelessDialog::setStyleSheetFile(const QString& fileName) { + QFile globalStyleSheet(Application::resourcesPath() + "styles/global.qss"); + QFile styleSheet(Application::resourcesPath() + fileName); + if (styleSheet.open(QIODevice::ReadOnly) && globalStyleSheet.open(QIODevice::ReadOnly) ) { + QDir::setCurrent(Application::resourcesPath()); + setStyleSheet(globalStyleSheet.readAll() + styleSheet.readAll()); + } +} + +void FramelessDialog::showEvent(QShowEvent* event) { + // move to upper left corner + move(parentWidget()->geometry().topLeft()); + + // keep full app height + setFixedHeight(parentWidget()->size().height()); + + // resize parrent if width is smaller than this dialog + if (parentWidget()->size().width() < size().width()) { + parentWidget()->resize(size().width(), parentWidget()->size().height()); + } +} +void FramelessDialog::mousePressEvent(QMouseEvent* mouseEvent) { + if (abs(mouseEvent->pos().x() - size().width()) < RESIZE_HANDLE_WIDTH && mouseEvent->button() == Qt::LeftButton) { + _isResizing = true; + QApplication::setOverrideCursor(Qt::SizeHorCursor); + } +} + +void FramelessDialog::mouseReleaseEvent(QMouseEvent* mouseEvent) { + QApplication::restoreOverrideCursor(); + _isResizing = false; +} + +void FramelessDialog::mouseMoveEvent(QMouseEvent* mouseEvent) { + if (_isResizing) { + resize(mouseEvent->pos().x(), size().height()); + } +} diff --git a/interface/src/ui/FramelessDialog.h b/interface/src/ui/FramelessDialog.h new file mode 100644 index 0000000000..db9f6dfd6c --- /dev/null +++ b/interface/src/ui/FramelessDialog.h @@ -0,0 +1,38 @@ +// +// FramelessDialog.h +// interface/src/ui +// +// Created by Stojce Slavkovski on 2/20/14. +// Copyright 2014 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 +// + + +#ifndef hifi_FramelessDialog_h +#define hifi_FramelessDialog_h + +#include + +class FramelessDialog : public QDialog { + Q_OBJECT + +public: + FramelessDialog(QWidget* parent = 0, Qt::WindowFlags flags = 0); + void setStyleSheetFile(const QString& fileName); + +protected: + virtual void mouseMoveEvent(QMouseEvent* mouseEvent); + virtual void mousePressEvent(QMouseEvent* mouseEvent); + virtual void mouseReleaseEvent(QMouseEvent* mouseEvent); + virtual void showEvent(QShowEvent* event); + + bool eventFilter(QObject* sender, QEvent* event); + +private: + bool _isResizing; + +}; + +#endif // hifi_FramelessDialog_h diff --git a/interface/src/ui/ModelsBrowser.cpp b/interface/src/ui/ModelsBrowser.cpp index 6c421863c8..77e056bdd3 100644 --- a/interface/src/ui/ModelsBrowser.cpp +++ b/interface/src/ui/ModelsBrowser.cpp @@ -65,7 +65,7 @@ static const QString propertiesIds[MODEL_METADATA_COUNT] = { }; ModelsBrowser::ModelsBrowser(ModelType modelsType, QWidget* parent) : - QWidget(parent), + QWidget(parent, Qt::WindowStaysOnTopHint), _handler(new ModelHandler(modelsType)) { connect(_handler, SIGNAL(doneDownloading()), SLOT(resizeView())); diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp new file mode 100644 index 0000000000..d1c9b4f6ca --- /dev/null +++ b/interface/src/ui/PreferencesDialog.cpp @@ -0,0 +1,163 @@ +// +// PreferencesDialog.cpp +// interface/src/ui +// +// Created by Stojce Slavkovski on 2/20/14. +// Copyright 2014 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 +// + + +#include "Application.h" +#include "Menu.h" +#include "PreferencesDialog.h" +#include "ModelsBrowser.h" + +const int SCROLL_PANEL_BOTTOM_MARGIN = 30; +const int OK_BUTTON_RIGHT_MARGIN = 30; +const int BUTTONS_TOP_MARGIN = 24; + +PreferencesDialog::PreferencesDialog(QWidget* parent, Qt::WindowFlags flags) : FramelessDialog(parent, flags) { + + ui.setupUi(this); + setStyleSheetFile("styles/preferences.qss"); + loadPreferences(); + connect(ui.closeButton, &QPushButton::clicked, this, &QDialog::close); + + connect(ui.buttonBrowseHead, &QPushButton::clicked, this, &PreferencesDialog::openHeadModelBrowser); + connect(ui.buttonBrowseBody, &QPushButton::clicked, this, &PreferencesDialog::openBodyModelBrowser); +} + +void PreferencesDialog::accept() { + savePreferences(); + close(); +} + +void PreferencesDialog::setHeadUrl(QString modelUrl) { + ui.faceURLEdit->setText(modelUrl); + setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint); +} + +void PreferencesDialog::setSkeletonUrl(QString modelUrl) { + ui.skeletonURLEdit->setText(modelUrl); + setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint); +} + +void PreferencesDialog::openHeadModelBrowser() { + setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint); + ModelsBrowser modelBrowser(Head); + connect(&modelBrowser, &ModelsBrowser::selected, this, &PreferencesDialog::setHeadUrl); + modelBrowser.browse(); +} + +void PreferencesDialog::openBodyModelBrowser() { + setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint); + ModelsBrowser modelBrowser(Skeleton); + connect(&modelBrowser, &ModelsBrowser::selected, this, &PreferencesDialog::setSkeletonUrl); + modelBrowser.browse(); +} + +void PreferencesDialog::resizeEvent(QResizeEvent *resizeEvent) { + + // keep buttons panel at the bottom + ui.buttonsPanel->setGeometry(0, size().height() - ui.buttonsPanel->height(), size().width(), ui.buttonsPanel->height()); + + // set width and height of srcollarea to match bottom panel and width + ui.scrollArea->setGeometry(ui.scrollArea->geometry().x(), ui.scrollArea->geometry().y(), + size().width(), + size().height() - ui.buttonsPanel->height() - + SCROLL_PANEL_BOTTOM_MARGIN - ui.scrollArea->geometry().y()); + + // move Save button to left position + ui.defaultButton->move(size().width() - OK_BUTTON_RIGHT_MARGIN - ui.defaultButton->size().width(), BUTTONS_TOP_MARGIN); + + // move Save button to left position + ui.cancelButton->move(ui.defaultButton->pos().x() - ui.cancelButton->size().width(), BUTTONS_TOP_MARGIN); + + // move close button + ui.closeButton->move(size().width() - OK_BUTTON_RIGHT_MARGIN - ui.closeButton->size().width(), ui.closeButton->pos().y()); +} + +void PreferencesDialog::loadPreferences() { + + MyAvatar* myAvatar = Application::getInstance()->getAvatar(); + Menu* menuInstance = Menu::getInstance(); + + _displayNameString = myAvatar->getDisplayName(); + ui.displayNameEdit->setText(_displayNameString); + + _faceURLString = myAvatar->getHead()->getFaceModel().getURL().toString(); + ui.faceURLEdit->setText(_faceURLString); + + _skeletonURLString = myAvatar->getSkeletonModel().getURL().toString(); + ui.skeletonURLEdit->setText(_skeletonURLString); + + ui.pupilDilationSlider->setValue(myAvatar->getHead()->getPupilDilation() * + ui.pupilDilationSlider->maximum()); + + ui.faceshiftEyeDeflectionSider->setValue(menuInstance->getFaceshiftEyeDeflection() * + ui.faceshiftEyeDeflectionSider->maximum()); + + ui.audioJitterSpin->setValue(menuInstance->getAudioJitterBufferSamples()); + + ui.fieldOfViewSpin->setValue(menuInstance->getFieldOfView()); + + ui.leanScaleSpin->setValue(myAvatar->getLeanScale()); + + ui.avatarScaleSpin->setValue(myAvatar->getScale()); + + ui.maxVoxelsSpin->setValue(menuInstance->getMaxVoxels()); + + ui.maxVoxelsPPSSpin->setValue(menuInstance->getMaxVoxelPacketsPerSecond()); +} + +void PreferencesDialog::savePreferences() { + + MyAvatar* myAvatar = Application::getInstance()->getAvatar(); + bool shouldDispatchIdentityPacket = false; + + QString displayNameStr(ui.displayNameEdit->text()); + if (displayNameStr != _displayNameString) { + myAvatar->setDisplayName(displayNameStr); + shouldDispatchIdentityPacket = true; + } + + QUrl faceModelURL(ui.faceURLEdit->text()); + if (faceModelURL.toString() != _faceURLString) { + // change the faceModelURL in the profile, it will also update this user's BlendFace + myAvatar->setFaceModelURL(faceModelURL); + shouldDispatchIdentityPacket = true; + } + + QUrl skeletonModelURL(ui.skeletonURLEdit->text()); + if (skeletonModelURL.toString() != _skeletonURLString) { + // change the skeletonModelURL in the profile, it will also update this user's Body + myAvatar->setSkeletonModelURL(skeletonModelURL); + shouldDispatchIdentityPacket = true; + } + + if (shouldDispatchIdentityPacket) { + myAvatar->sendIdentityPacket(); + } + + myAvatar->getHead()->setPupilDilation(ui.pupilDilationSlider->value() / (float)ui.pupilDilationSlider->maximum()); + myAvatar->setLeanScale(ui.leanScaleSpin->value()); + myAvatar->setClampedTargetScale(ui.avatarScaleSpin->value()); + + Application::getInstance()->getVoxels()->setMaxVoxels(ui.maxVoxelsSpin->value()); + Application::getInstance()->resizeGL(Application::getInstance()->getGLWidget()->width(), + Application::getInstance()->getGLWidget()->height()); + + Menu::getInstance()->setFieldOfView(ui.fieldOfViewSpin->value()); + + Menu::getInstance()->setFaceshiftEyeDeflection(ui.faceshiftEyeDeflectionSider->value() / + (float)ui.faceshiftEyeDeflectionSider->maximum()); + Menu::getInstance()->setMaxVoxelPacketsPerSecond(ui.maxVoxelsPPSSpin->value()); + + Menu::getInstance()->setAudioJitterBufferSamples(ui.audioJitterSpin->value()); + + Application::getInstance()->resizeGL(Application::getInstance()->getGLWidget()->width(), + Application::getInstance()->getGLWidget()->height()); +} diff --git a/interface/src/ui/PreferencesDialog.h b/interface/src/ui/PreferencesDialog.h new file mode 100644 index 0000000000..c9514e584a --- /dev/null +++ b/interface/src/ui/PreferencesDialog.h @@ -0,0 +1,47 @@ +// +// PreferencesDialog.h +// interface/src/ui +// +// Created by Stojce Slavkovski on 2/20/14. +// Copyright 2014 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 +// + +#ifndef hifi_PreferencesDialog_h +#define hifi_PreferencesDialog_h + +#include "FramelessDialog.h" +#include "ui_preferencesDialog.h" + +#include + +class PreferencesDialog : public FramelessDialog { + Q_OBJECT + +public: + PreferencesDialog(QWidget* parent = 0, Qt::WindowFlags flags = 0); + +protected: + void resizeEvent(QResizeEvent* resizeEvent); + +private: + void loadPreferences(); + void savePreferences(); + void openHeadModelBrowser(); + void openBodyModelBrowser(); + + Ui_PreferencesDialog ui; + QString _faceURLString; + QString _skeletonURLString; + QString _displayNameString; + +private slots: + void accept(); + void setHeadUrl(QString modelUrl); + void setSkeletonUrl(QString modelUrl); + +}; + +#endif // hifi_PreferencesDialog_h diff --git a/interface/ui/preferencesDialog.ui b/interface/ui/preferencesDialog.ui new file mode 100644 index 0000000000..a151a499c6 --- /dev/null +++ b/interface/ui/preferencesDialog.ui @@ -0,0 +1,1375 @@ + + + PreferencesDialog + + + + 0 + 0 + 638 + 652 + + + + + 0 + 0 + + + + + 610 + 0 + + + + 0.950000000000000 + + + + + 0 + 560 + 611 + 97 + + + + + 0 + 0 + + + + + 0 + 97 + + + + + Arial + + + + background-color: #0e7077 + + + + + 310 + 24 + 91 + 50 + + + + + 0 + 0 + + + + + 0 + 50 + + + + + Arial + 18 + 50 + false + + + + + + + Cancel + + + + + + 400 + 24 + 188 + 50 + + + + + 0 + 0 + + + + + 188 + 49 + + + + + Arial + 18 + + + + background-color: #fff; +color: #0e7077 + + + Save all changes + + + true + + + + + + + 0 + 30 + 615 + 491 + + + + QFrame::NoFrame + + + QFrame::Plain + + + 0 + + + true + + + + + 0 + 0 + 615 + 833 + + + + + 0 + + + 30 + + + 0 + + + 30 + + + 30 + + + + + + 0 + 0 + + + + + Arial + 24 + + + + color: #0e7077 + + + Avatar + + + 25 + + + + + + + + + + + 0 + 0 + + + + + 0 + 30 + + + + + Arial + 16 + + + + color: #0e7077 + + + <html><head/><body><p>Avatar display name <span style=" color:#909090;">(optional)</span></p></body></html> + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + displayNameEdit + + + + + + + + 0 + 0 + + + + + 280 + 0 + + + + + Arial + + + + Qt::LeftToRight + + + + + + Not showing a name + + + + + + + + 0 + 0 + + + + + 0 + 30 + + + + + Arial + 16 + + + + color: #0e7077 + + + Head + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + 0 + + + faceURLEdit + + + + + + + + + + 0 + 0 + + + + + Arial + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 0 + 0 + + + + + 30 + 30 + + + + + 30 + 30 + + + + + + + + + + + 30 + 30 + + + + + + + + + + + 0 + 0 + + + + + 0 + 30 + + + + + Arial + 16 + + + + color: #0e7077 + + + Body + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + skeletonURLEdit + + + + + + + + + + 0 + 0 + + + + + Arial + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 0 + 0 + + + + + 30 + 30 + + + + + 30 + 30 + + + + + + + + + + + 30 + 30 + + + + + + + + + + Qt::Vertical + + + + 0 + 35 + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + Arial + 24 + + + + color: #0e7077 + + + Advanced Tuning + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 25 + + + + + + + + 0 + 0 + + + + + Arial + 16 + + + + true + + + color: rgb(51, 51, 51); + + + It's not recomended that you play with these settings unless you've looked into exactly what they do. + + + false + + + true + + + + + + + + 0 + 0 + + + + + 0 + 40 + + + + + Arial + 20 + 50 + false + + + + color: #0e7077 + + + Avatar + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + 0 + + + 10 + + + 0 + + + 10 + + + + + + Arial + + + + + + + Vertical field of view + + + 15 + + + fieldOfViewSpin + + + + + + + + Arial + + + + Qt::Horizontal + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + 95 + 36 + + + + + 95 + 36 + + + + + Arial + + + + 1 + + + 180 + + + + + + + + + 0 + + + 10 + + + 10 + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 25 + + + + + Arial + + + + color: rgb(51, 51, 51) + + + Lean scale (applies to Faceshift users) + + + 15 + + + leanScaleSpin + + + + + + + + Arial + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 10 + + + + + + + + + 0 + 0 + + + + + 95 + 36 + + + + + 70 + 16777215 + + + + + Arial + + + + + + + + + + 0 + + + 10 + + + 0 + + + 10 + + + + + + Arial + + + + color: rgb(51, 51, 51) + + + Avatar scale <span style=" color:#909090;">(default is 1.0)</span> + + + 15 + + + avatarScaleSpin + + + + + + + + Arial + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 95 + 36 + + + + + 70 + 16777215 + + + + + Arial + + + + + + + + + + 0 + + + 10 + + + 0 + + + 10 + + + + + + Arial + + + + color: rgb(51, 51, 51) + + + Pupil dillation + + + 15 + + + pupilDilationSlider + + + + + + + + Arial + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 125 + 0 + + + + + Arial + + + + Qt::Horizontal + + + + + + + + + 0 + + + 10 + + + 0 + + + 10 + + + + + + Arial + + + + color: rgb(51, 51, 51) + + + Audio Jitter Buffer Samples (0 for automatic) + + + 15 + + + audioJitterSpin + + + + + + + + Arial + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 95 + 36 + + + + + 70 + 16777215 + + + + + Arial + + + + -10000 + + + 10000 + + + 1 + + + + + + + + + 0 + + + 10 + + + 0 + + + 10 + + + + + + Arial + + + + color: rgb(51, 51, 51) + + + Faceshift eye detection + + + 15 + + + faceshiftEyeDeflectionSider + + + + + + + + Arial + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 125 + 0 + + + + + Arial + + + + Qt::Horizontal + + + + + + + + + + 0 + 0 + + + + + 0 + 40 + + + + + Arial + 20 + 50 + false + + + + color: #0e7077 + + + Voxels + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + 0 + + + 10 + + + 0 + + + 10 + + + + + + Arial + + + + color: rgb(51, 51, 51) + + + Maximum voxels + + + 15 + + + maxVoxelsSpin + + + + + + + + Arial + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 125 + 36 + + + + + Arial + + + + 5000000 + + + 50000 + + + + + + + + + 0 + + + 10 + + + 0 + + + 10 + + + + + + Arial + + + + Max voxels sent each second + + + 15 + + + maxVoxelsPPSSpin + + + + + + + + Arial + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 95 + 36 + + + + + 70 + 16777215 + + + + + Arial + + + + 60 + + + 6000 + + + 10 + + + + + + + + + + + + 540 + 24 + 31 + 31 + + + + + PreferAntialias + + + + + + + + + + FramelessDialog + 1 + + + + + + cancelButton + clicked() + PreferencesDialog + close() + + + 495 + 749 + + + 528 + 0 + + + + + defaultButton + clicked() + PreferencesDialog + accept() + + + 504 + 749 + + + 20 + 20 + + + + +