diff --git a/interface/resources/styles/Inconsolata.otf b/interface/resources/styles/Inconsolata.otf new file mode 100644 index 0000000000..348889828d Binary files /dev/null and b/interface/resources/styles/Inconsolata.otf differ diff --git a/interface/resources/styles/log_dialog.qss b/interface/resources/styles/log_dialog.qss new file mode 100644 index 0000000000..fe3675f682 --- /dev/null +++ b/interface/resources/styles/log_dialog.qss @@ -0,0 +1,7 @@ +QPlainTextEdit { + font-family: Inconsolata, Lucida Console, Andale Mono, Monaco; + font-size: 16px; + padding-left: 28px; + color: #333333; + background-color: #FFFFFF; +} diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4aacc50291..8a2e3ed946 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -143,11 +143,17 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _pasteMode(false) { _applicationStartupTime = startup_time; + + switchToResourcesParentIfRequired(); + QFontDatabase::addApplicationFont("resources/styles/Inconsolata.otf"); _window->setWindowTitle("Interface"); - - qDebug( "[VERSION] Build sequence: %i", BUILD_VERSION); - + qInstallMessageHandler(messageHandler); + + // call Menu getInstance static method to set up the menu + _window->setMenuBar(Menu::getInstance()); + + qDebug("[VERSION] Build sequence: %i", BUILD_VERSION); unsigned int listenPort = 0; // bind to an ephemeral port by default const char** constArgv = const_cast(argv); @@ -173,16 +179,9 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : // network receive thread and voxel parsing thread are both controlled by the --nonblocking command line _enableProcessVoxelsThread = _enableNetworkThread = !cmdOptionExists(argc, constArgv, "--nonblocking"); - - // setup QSettings -#ifdef Q_OS_MAC - QString resourcesPath = QCoreApplication::applicationDirPath() + "/../Resources"; -#else - QString resourcesPath = QCoreApplication::applicationDirPath() + "/resources"; -#endif - + // read the ApplicationInfo.ini file for Name/Version/Domain information - QSettings applicationInfo(resourcesPath + "/info/ApplicationInfo.ini", QSettings::IniFormat); + QSettings applicationInfo("resources/info/ApplicationInfo.ini", QSettings::IniFormat); // set the associated application properties applicationInfo.beginGroup("INFO"); @@ -191,11 +190,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : setApplicationVersion(applicationInfo.value("version").toString()); setOrganizationName(applicationInfo.value("organizationName").toString()); setOrganizationDomain(applicationInfo.value("organizationDomain").toString()); - + _settings = new QSettings(this); - - // call Menu getInstance static method to set up the menu - _window->setMenuBar(Menu::getInstance()); // Check to see if the user passed in a command line option for loading a local // Voxel File. @@ -251,6 +247,9 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : } Application::~Application() { + + qInstallMessageHandler(NULL); + // make sure we don't call the idle timer any more delete idleTimer; @@ -4479,3 +4478,12 @@ void Application::loadScript() { // restore the main window's active state _window->activateWindow(); } + +void Application::toggleLogDialog() { + if (! _logDialog) { + _logDialog = new LogDialog(_glWidget); + _logDialog->show(); + } else { + _logDialog->close(); + } +} diff --git a/interface/src/Application.h b/interface/src/Application.h index 5f8aaffd23..7680388e9f 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -67,6 +68,7 @@ #include "ui/VoxelStatsDialog.h" #include "ui/RearMirrorTools.h" #include "ui/LodToolsDialog.h" +#include "ui/LogDialog.h" #include "ParticleTreeRenderer.h" #include "ParticleEditHandle.h" @@ -222,7 +224,7 @@ public slots: void decreaseVoxelSize(); void increaseVoxelSize(); void loadScript(); - + void toggleLogDialog(); private slots: @@ -503,6 +505,8 @@ private: std::vector _voxelFades; std::vector _avatarFades; + + QPointer _logDialog; }; #endif /* defined(__interface__Application__) */ diff --git a/interface/src/LogDisplay.cpp b/interface/src/LogDisplay.cpp index 247ea4beb5..84a1abd364 100644 --- a/interface/src/LogDisplay.cpp +++ b/interface/src/LogDisplay.cpp @@ -91,6 +91,7 @@ void LogDisplay::setCharacterSize(unsigned width, unsigned height) { void LogDisplay::addMessage(const char* ptr) { pthread_mutex_lock(& _mutex); + emit logReceived(ptr); // T-pipe, if requested if (_stream != 0l) { @@ -118,7 +119,7 @@ void LogDisplay::addMessage(const char* ptr) { _writePos = _chars; } - if (++_writtenInLine >= _lineLength || c == '\0') { + if (c == '\0') { // new line? store its start to the line buffer and mark next line as empty ++_lastLinePos; @@ -148,13 +149,24 @@ void LogDisplay::addMessage(const char* ptr) { // remember start position in character buffer for next line and reset character count _writeLineStartPos = _writePos; - _writtenInLine = 0; } } pthread_mutex_unlock(& _mutex); } +QStringList LogDisplay::getLogData() { + // wait for adding new log data whilr iterating over _lines + pthread_mutex_lock(& _mutex); + QStringList list; + int i = 0; + while (_lines[i] != *_lastLinePos) { + list.append(_lines[i++]); + } + pthread_mutex_unlock(& _mutex); + return list; +} + // // Rendering // diff --git a/interface/src/LogDisplay.h b/interface/src/LogDisplay.h index 6f90df3724..285325b180 100644 --- a/interface/src/LogDisplay.h +++ b/interface/src/LogDisplay.h @@ -14,7 +14,8 @@ #include "ui/TextRenderer.h" -class LogDisplay { +class LogDisplay : public QObject { + Q_OBJECT public: static LogDisplay instance; @@ -43,6 +44,11 @@ public: static unsigned const LINE_BUFFER_SIZE = 256; // number of lines that are buffered static unsigned const MAX_MESSAGE_LENGTH = 512; // maximum number of characters for a message + QStringList getLogData(); + +signals: + void logReceived(QString message); + private: // use static 'instance' to access the single instance LogDisplay(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index ab725da812..38f4ae3bae 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -265,7 +265,7 @@ Menu::Menu() : addDisabledActionAndSeparator(viewMenu, "Stats"); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Slash); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Log, Qt::CTRL | Qt::Key_L); + addActionToQMenuAndActionHash(viewMenu, MenuOption::Log, Qt::CTRL | Qt::Key_L, appInstance, SLOT(toggleLogDialog())); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Oscilloscope, 0, true); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Bandwidth, 0, true); addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0, this, SLOT(bandwidthDetails())); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 44e5505f2d..c5742cc570 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -146,7 +146,6 @@ private: int _boundaryLevelAdjust; QAction* _useVoxelShader; int _maxVoxelPacketsPerSecond; - QMenu* _activeScriptsMenu; }; diff --git a/interface/src/ui/LogDialog.cpp b/interface/src/ui/LogDialog.cpp new file mode 100644 index 0000000000..013c60d993 --- /dev/null +++ b/interface/src/ui/LogDialog.cpp @@ -0,0 +1,75 @@ +// +// LogDialog.cpp +// interface +// +// Created by Stojce Slavkovski on 12/12/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#include +#include +#include + +#include "SharedUtil.h" +#include "ui/LogDialog.h" +#include "LogDisplay.h" + +const int INITIAL_WIDTH = 720; +const float INITIAL_HEIGHT_RATIO = 0.6f; + +int cursorMeta = qRegisterMetaType("QTextCursor"); +int blockMeta = qRegisterMetaType("QTextBlock"); + +LogDialog::LogDialog(QWidget* parent) : QDialog(parent, Qt::Dialog) { + + setWindowTitle("Log"); + + _logTextBox = new QPlainTextEdit(this); + _logTextBox->setReadOnly(true); + _logTextBox->show(); + + switchToResourcesParentIfRequired(); + QFile styleSheet("resources/styles/log_dialog.qss"); + + if (styleSheet.open(QIODevice::ReadOnly)) { + setStyleSheet(styleSheet.readAll()); + } + + QDesktopWidget desktop; + QRect screen = desktop.screenGeometry(); + resize(INITIAL_WIDTH, static_cast(screen.height() * INITIAL_HEIGHT_RATIO)); + move(screen.center() - rect().center()); + + setAttribute(Qt::WA_DeleteOnClose); +} + +LogDialog::~LogDialog() { + deleteLater(); +} + +void LogDialog::showEvent(QShowEvent *e) { + _logTextBox->clear(); + + pthread_mutex_lock(& _mutex); + QStringList _logData = LogDisplay::instance.getLogData(); + + connect(&LogDisplay::instance, &LogDisplay::logReceived, this, &LogDialog::appendLogLine); + for(int i = 0; i < _logData.size(); ++i) { + appendLogLine(_logData[i]); + } + + pthread_mutex_unlock(& _mutex); +} + +void LogDialog::resizeEvent(QResizeEvent *e) { + _logTextBox->resize(width(), height()); +} + +void LogDialog::appendLogLine(QString logLine) { + if (isVisible()) { + pthread_mutex_lock(& _mutex); + _logTextBox->appendPlainText(logLine.simplified()); + pthread_mutex_unlock(& _mutex); + _logTextBox->ensureCursorVisible(); + } +} diff --git a/interface/src/ui/LogDialog.h b/interface/src/ui/LogDialog.h new file mode 100644 index 0000000000..808ac4a485 --- /dev/null +++ b/interface/src/ui/LogDialog.h @@ -0,0 +1,36 @@ +// +// LogDialog.h +// interface +// +// Created by Stojce Slavkovski on 12/12/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__LogDialog__ +#define __interface__LogDialog__ + +#include +#include + +class LogDialog : public QDialog { + Q_OBJECT + +public: + LogDialog(QWidget* parent); + ~LogDialog(); + +public slots: + void appendLogLine(QString logLine); + +protected: + void resizeEvent(QResizeEvent* e); + void showEvent(QShowEvent* e); + +private: + QPlainTextEdit* _logTextBox; + pthread_mutex_t _mutex; + +}; + +#endif +