diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2015-10-30 09:01:32 +0100 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2015-10-30 09:01:32 +0100 |
commit | d785d3616500d5846ac8c5f5a6347da832a593b4 (patch) | |
tree | ac670a125c5b880ad7e4b4f24a8635da4e66f0da /gui | |
parent | 232c2ba8aca7900eaa950c48813ddfaca8a749a8 (diff) | |
parent | 9b736d361bcde7a2ddaf3fe54b471c0e658e94f4 (diff) |
Merge branch 'unstable' into trackhat
* unstable:
cmake: cleanup hydra
rename gui directory
move to subdirectory-based build system
cmake: switch to GNU CC 5.2.0 in mingw-w64 toolchain file
rift-080: forgot ovr_Initialize()
rift 025: fix name
Diffstat (limited to 'gui')
38 files changed, 5677 insertions, 0 deletions
diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt new file mode 100644 index 00000000..0b20bc9c --- /dev/null +++ b/gui/CMakeLists.txt @@ -0,0 +1,67 @@ +opentrack_boilerplate(opentrack NO-LIBRARY) + +if(UNIX OR APPLE) + target_include_directories(opentrack "${CMAKE_SOURCE_DIR}/qxt-mini") + if(APPLE) + set(qxt-plat mac) + else() + set(qxt-plat x11) + endif() + file(GLOB qxt-mini-c + ${CMAKE_SOURCE_DIR}/qxt-mini/*.h + ${CMAKE_SOURCE_DIR}/qxt-mini/qxtglobalshortcut.cpp + ${CMAKE_SOURCE_DIR}/qxt-mini/plat/qxtglobalshortcut_${qxt-plat}.cpp + ) + opentrack_qt(qxt-mini) + add_library(opentrack-qxt-mini STATIC ${qxt-mini-all}) + target_link_libraries(opentrack-qxt-mini ${MY_QT_LIBS}) + if(NOT APPLE) + target_link_libraries(opentrack-qxt-mini X11) + endif() +endif() + +if(WIN32) + SET(SDK_CONSOLE_DEBUG FALSE CACHE BOOL "Console window visible at runtime") +endif() + +if(WIN32 AND NOT SDK_CONSOLE_DEBUG) + set(opentrack-win32-executable WIN32) +else() + set(opentrack-win32-executable "") +endif() + +if(UNIX OR APPLE) + list(APPEND opentrack-c ${CMAKE_SOURCE_DIR}/qxt-mini/qxtglobalshortcut.h) +endif() +opentrack_qt(opentrack) +add_executable(opentrack ${opentrack-win32-executable} ${opentrack-all}) +opentrack_compat(opentrack) +if(NOT WIN32) + set_target_properties(opentrack PROPERTIES SUFFIX ".bin") +endif() + +target_link_libraries(opentrack + opentrack-api opentrack-version opentrack-pose-widget opentrack-spline-widget + opentrack-tracker-pt opentrack-filter-accela +) + +if(APPLE) + SET_TARGET_PROPERTIES(opentrack-qxt-mini PROPERTIES LINK_FLAGS "-framework Carbon -framework CoreFoundation") +endif() +if(UNIX OR APPLE) + target_link_libraries(opentrack opentrack-qxt-mini) +endif() +link_with_dinput8(opentrack) +target_link_libraries(opentrack ${MY_QT_LIBS}) + +if(APPLE) + # for process detector + target_link_libraries(opentrack proc) +endif() + +if(LINUX) + # for process detector + target_link_libraries(opentrack procps) +endif() + +install(TARGETS opentrack DESTINATION .) diff --git a/gui/curve-config.cpp b/gui/curve-config.cpp new file mode 100644 index 00000000..2e9065b4 --- /dev/null +++ b/gui/curve-config.cpp @@ -0,0 +1,81 @@ +/* Copyright (c) 2014-2015, Stanislaw Halik <sthalik@misaki.pl> + + * Permission to use, copy, modify, and/or distribute this + * software for any purpose with or without fee is hereby granted, + * provided that the above copyright notice and this permission + * notice appear in all copies. + */ + +#include "curve-config.h" +#include "opentrack/main-settings.hpp" +MapWidget::MapWidget(Mappings& m, main_settings& s) : + m(m) +{ + ui.setupUi( this ); + + // rest of mapping settings taken care of by options::value<t> + m.load_mappings(); + + { + struct { + QFunctionConfigurator* qfc; + Axis axis; + QCheckBox* checkbox; + bool altp; + } qfcs[] = + { + { ui.rxconfig, Yaw, nullptr, false }, + { ui.ryconfig, Pitch, nullptr, false }, + { ui.rzconfig, Roll, nullptr, false }, + { ui.txconfig, TX, nullptr, false }, + { ui.tyconfig, TY, nullptr, false }, + { ui.tzconfig, TZ, nullptr, false }, + + { ui.rxconfig_alt, Yaw, ui.rx_altp, true }, + { ui.ryconfig_alt, Pitch, ui.ry_altp, true }, + { ui.rzconfig_alt, Roll, ui.rz_altp, true }, + { ui.txconfig_alt, TX, ui.tx_altp, true }, + { ui.tyconfig_alt, TY, ui.ty_altp, true }, + { ui.tzconfig_alt, TZ, ui.tz_altp, true }, + { nullptr, Yaw, nullptr, false } + }; + + for (int i = 0; qfcs[i].qfc; i++) + { + const bool altp = qfcs[i].altp; + Mapping& axis = m(qfcs[i].axis); + Map* conf = altp ? &axis.curveAlt : &axis.curve; + const auto& name = qfcs[i].altp ? axis.name2 : axis.name1; + if (altp) + { + QFunctionConfigurator& qfc = *qfcs[i].qfc; + connect(qfcs[i].checkbox, &QCheckBox::toggled, + [&](bool f) -> void {qfc.setEnabled(f); qfc.force_redraw();}); + qfc.setEnabled(qfcs[i].checkbox->isChecked()); + qfc.force_redraw(); + } + qfcs[i].qfc->setConfig(conf, name); + } + } + + setFont(qApp->font()); + connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(doOK())); + connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(doCancel())); + + tie_setting(s.a_x.altp, ui.tx_altp); + tie_setting(s.a_y.altp, ui.ty_altp); + tie_setting(s.a_z.altp, ui.tz_altp); + tie_setting(s.a_yaw.altp, ui.rx_altp); + tie_setting(s.a_pitch.altp, ui.ry_altp); + tie_setting(s.a_roll.altp, ui.rz_altp); +} + +void MapWidget::doOK() { + m.save_mappings(); + this->close(); +} + +void MapWidget::doCancel() { + m.invalidate_unsaved(); + this->close(); +} diff --git a/gui/curve-config.h b/gui/curve-config.h new file mode 100644 index 00000000..0cbc7055 --- /dev/null +++ b/gui/curve-config.h @@ -0,0 +1,18 @@ +#pragma once +#include <QWidget> +#include "opentrack/mappings.hpp" +#include "ui_mapping.h" + +class MapWidget: public QWidget +{ + Q_OBJECT +public: + MapWidget(Mappings &m, main_settings &s); +private: + Ui::UICCurveConfigurationDialog ui; + Mappings& m; + void closeEvent(QCloseEvent *) override { doCancel(); } +private slots: + void doOK(); + void doCancel(); +}; diff --git a/gui/facetracknoir.ico b/gui/facetracknoir.ico Binary files differnew file mode 100755 index 00000000..b5f34db3 --- /dev/null +++ b/gui/facetracknoir.ico diff --git a/gui/facetracknoir.rc b/gui/facetracknoir.rc new file mode 100644 index 00000000..020ffe97 --- /dev/null +++ b/gui/facetracknoir.rc @@ -0,0 +1,2 @@ +#include <windows.h> +IDI_ICON1 ICON "facetracknoir.ico" diff --git a/gui/images/curves.png b/gui/images/curves.png Binary files differnew file mode 100644 index 00000000..3f953a0a --- /dev/null +++ b/gui/images/curves.png diff --git a/gui/images/facetracknoir.png b/gui/images/facetracknoir.png Binary files differnew file mode 100755 index 00000000..4f17de81 --- /dev/null +++ b/gui/images/facetracknoir.png diff --git a/gui/images/filter-16.png b/gui/images/filter-16.png Binary files differnew file mode 100644 index 00000000..ecde6a10 --- /dev/null +++ b/gui/images/filter-16.png diff --git a/gui/images/no-feed.png b/gui/images/no-feed.png Binary files differnew file mode 100644 index 00000000..02aa227a --- /dev/null +++ b/gui/images/no-feed.png diff --git a/gui/images/settings16.png b/gui/images/settings16.png Binary files differnew file mode 100644 index 00000000..3b31623b --- /dev/null +++ b/gui/images/settings16.png diff --git a/gui/images/tools.png b/gui/images/tools.png Binary files differnew file mode 100644 index 00000000..2da8f9f5 --- /dev/null +++ b/gui/images/tools.png diff --git a/gui/images/trackhat-clip-left.png b/gui/images/trackhat-clip-left.png Binary files differnew file mode 100644 index 00000000..cdde2160 --- /dev/null +++ b/gui/images/trackhat-clip-left.png diff --git a/gui/images/trackhat-clip-right.png b/gui/images/trackhat-clip-right.png Binary files differnew file mode 100644 index 00000000..59f8ae71 --- /dev/null +++ b/gui/images/trackhat-clip-right.png diff --git a/gui/images/trackhat-hat.png b/gui/images/trackhat-hat.png Binary files differnew file mode 100644 index 00000000..252c2e6b --- /dev/null +++ b/gui/images/trackhat-hat.png diff --git a/gui/install-driver-dialog.ui b/gui/install-driver-dialog.ui new file mode 100644 index 00000000..3ef3bb2f --- /dev/null +++ b/gui/install-driver-dialog.ui @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>DriverDialog</class> + <widget class="QDialog" name="DriverDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>415</width> + <height>94</height> + </rect> + </property> + <property name="windowTitle"> + <string>PS3 Eye driver missing</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string><html><head/><body><p>The PS3 Eye driver or camera is missing. Please install the driver or plug in the camera and restart the program. Thanks!</p></body></html></string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string><html><head/><body><p>Driver download: <a href="https://mega.nz/#!QkAjnBwD!-ULu08uFwGK5hl7ugbFZfuAw2hIdFpwVtn-jewThrN8"><span style=" text-decoration: underline; color:#0000ff;">mega.nz</span></a></p></body></html></string> + </property> + <property name="openExternalLinks"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/gui/keyboard.h b/gui/keyboard.h new file mode 100644 index 00000000..62a9ce20 --- /dev/null +++ b/gui/keyboard.h @@ -0,0 +1,50 @@ +#pragma once +#include "ui_keyboard_listener.h" +#ifdef _WIN32 +#include "opentrack/win32-shortcuts.h" +#include "opentrack/shortcuts.h" +#endif +#include <QLabel> +#include <QKeyEvent> +#include <QDebug> + +class KeyboardListener : public QLabel +{ + Q_OBJECT + Ui_keyboard_listener ui; +#ifdef _WIN32 + KeybindingWorker w; +#endif +public: + KeyboardListener(QWidget* parent = nullptr) : QLabel(parent) +#ifdef _WIN32 + , w([&](Key& k) + { + Qt::KeyboardModifiers m; + QKeySequence k_; + if (win_key::to_qt(k, k_, m)) + key_pressed(static_cast<QVariant>(k_).toInt() | m); + }, this->winId()) +#endif + { + ui.setupUi(this); + setFocusPolicy(Qt::StrongFocus); +#ifdef _WIN32 + w.start(); +#endif + } +#ifndef _WIN32 + void keyPressEvent(QKeyEvent* event) override + { + //qDebug() << "k" << (event->key() | event->modifiers()); + switch (event->key() | event->modifiers()) + { + default: + emit key_pressed(QKeySequence(event->key() | event->modifiers())); + break; + } + } +#endif +signals: + void key_pressed(QKeySequence k); +}; diff --git a/gui/keyboard_listener.ui b/gui/keyboard_listener.ui new file mode 100644 index 00000000..b6977df0 --- /dev/null +++ b/gui/keyboard_listener.ui @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>keyboard_listener</class> + <widget class="QLabel" name="keyboard_listener"> + <property name="windowModality"> + <enum>Qt::ApplicationModal</enum> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>224</width> + <height>33</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="windowTitle"> + <string>Bind a shortcut</string> + </property> + <property name="text"> + <string><html><head/><body><p>Press a key or close this window to remove the keybinding.</p></body></html></string> + </property> + <property name="textFormat"> + <enum>Qt::RichText</enum> + </property> + <property name="margin"> + <number>10</number> + </property> + </widget> + <resources/> + <connections/> +</ui> diff --git a/gui/main.cpp b/gui/main.cpp new file mode 100644 index 00000000..4e56b3df --- /dev/null +++ b/gui/main.cpp @@ -0,0 +1,100 @@ +#ifdef _WIN32 +# include <stdlib.h> +#endif + +#include "opentrack/opencv-camera-dialog.hpp" +#include "wizard.h" +#include "ui.h" +#include "opentrack/options.hpp" +#include "ui_install-driver-dialog.h" +using namespace options; +#include <QApplication> +#include <QCommandLineParser> +#include <QStyleFactory> +#include <QStringList> +#include <QMessageBox> +#include <memory> +#include <cstring> + +#ifdef _WIN32 +// workaround QTBUG-38598, allow for launching from another directory +static void add_program_library_path() +{ + char* p = _pgmptr; + char path[MAX_PATH+1]; + strcpy(path, p); + char* ptr = strrchr(path, '\\'); + if (ptr) + { + *ptr = '\0'; + QCoreApplication::addLibraryPath(path); + } +} +#endif + +int main(int argc, char** argv) +{ +#ifdef _WIN32 + add_program_library_path(); +#elif !defined(__linux) + // workaround QTBUG-38598 + QCoreApplication::addLibraryPath("."); +#endif + +#if defined(_WIN32) || defined(__APPLE__) + // qt5 designer-made controls look like shit on 'doze -sh 20140921 + // also our OSX look leaves a lot to be desired -sh 20150726 + { + const QStringList preferred { "fusion", "windowsvista", "macintosh", "windowsxp" }; + for (const auto& style_name : preferred) + { + QStyle* s = QStyleFactory::create(style_name); + if (s) + { + QApplication::setStyle(s); + break; + } + } + } +#endif + + QApplication::setAttribute(Qt::AA_X11InitThreads, true); + QApplication app(argc, argv); + + { + QSettings s(OPENTRACK_ORG); + if (!s.contains("wizard-run-once")) + { + s.setValue("wizard-run-once", true); + auto w = std::make_shared<Wizard>(); + w->show(); + app.exec(); + } + } + + if (get_camera_names().contains("PS3Eye Camera")) + { + auto w = std::make_shared<MainWindow>(); + + w->show(); + app.exec(); + } + else + { + struct Dialog : QDialog + { + Ui::DriverDialog dlg; + Dialog() + { + dlg.setupUi(this); + } + }; + Dialog().exec(); + } + + // on MSVC crashes in atexit +#ifdef _MSC_VER + TerminateProcess(GetCurrentProcess(), 0); +#endif + return 0; +} diff --git a/gui/main.ui b/gui/main.ui new file mode 100644 index 00000000..532d3124 --- /dev/null +++ b/gui/main.ui @@ -0,0 +1,1130 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <author>Lovecraftian Octopus</author> + <class>OpentrackUI</class> + <widget class="QMainWindow" name="OpentrackUI"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>693</width> + <height>575</height> + </rect> + </property> + <property name="windowIcon"> + <iconset resource="ui-res.qrc"> + <normaloff>:/images/facetracknoir.png</normaloff>:/images/facetracknoir.png</iconset> + </property> + <property name="styleSheet"> + <string notr="true">#video_feed { border: 0; } +</string> + </property> + <widget class="QWidget" name="content"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QFrame" name="frame"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <layout class="QGridLayout" name="gridLayout_5"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <item row="0" column="0"> + <widget class="QFrame" name="top"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QFrame" name="video_feed"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>480</width> + <height>360</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>480</width> + <height>360</height> + </size> + </property> + <widget class="QFrame" name="video_frame"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>480</width> + <height>360</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <widget class="QLabel" name="video_frame_label"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>480</width> + <height>360</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>480</width> + <height>360</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>480</width> + <height>360</height> + </size> + </property> + <property name="text"> + <string/> + </property> + </widget> + </widget> + </widget> + </item> + <item> + <widget class="QFrame" name="top_display"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <layout class="QVBoxLayout"> + <property name="spacing"> + <number>12</number> + </property> + <property name="leftMargin"> + <number>6</number> + </property> + <property name="topMargin"> + <number>12</number> + </property> + <property name="rightMargin"> + <number>8</number> + </property> + <property name="bottomMargin"> + <number>4</number> + </property> + <item> + <widget class="GLWidget" name="pose_display" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>110</width> + <height>120</height> + </size> + </property> + </widget> + </item> + <item> + <widget class="QGroupBox" name="box_raw_headpose"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string notr="true">Raw tracker data</string> + </property> + <layout class="QGridLayout" name="gridLayout_12"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="horizontalSpacing"> + <number>3</number> + </property> + <property name="verticalSpacing"> + <number>2</number> + </property> + <item row="0" column="1"> + <widget class="QLCDNumber" name="raw_x"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="lineWidth"> + <number>1</number> + </property> + <property name="smallDecimalPoint"> + <bool>true</bool> + </property> + <property name="digitCount"> + <number>4</number> + </property> + <property name="segmentStyle"> + <enum>QLCDNumber::Outline</enum> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="lblRotX_4"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="text"> + <string>yaw</string> + </property> + </widget> + </item> + <item row="2" column="2"> + <widget class="QLabel" name="lblRotZ_4"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="text"> + <string>roll</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="lblZ_4"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="autoFillBackground"> + <bool>false</bool> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="text"> + <string>TZ</string> + </property> + </widget> + </item> + <item row="1" column="2"> + <widget class="QLabel" name="lblRotY_4"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="text"> + <string>pitch</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLCDNumber" name="raw_y"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="lineWidth"> + <number>1</number> + </property> + <property name="smallDecimalPoint"> + <bool>true</bool> + </property> + <property name="digitCount"> + <number>4</number> + </property> + <property name="segmentStyle"> + <enum>QLCDNumber::Outline</enum> + </property> + </widget> + </item> + <item row="0" column="3"> + <widget class="QLCDNumber" name="raw_yaw"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="lineWidth"> + <number>1</number> + </property> + <property name="smallDecimalPoint"> + <bool>true</bool> + </property> + <property name="digitCount"> + <number>4</number> + </property> + <property name="segmentStyle"> + <enum>QLCDNumber::Outline</enum> + </property> + </widget> + </item> + <item row="2" column="3"> + <widget class="QLCDNumber" name="raw_roll"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="lineWidth"> + <number>1</number> + </property> + <property name="smallDecimalPoint"> + <bool>true</bool> + </property> + <property name="digitCount"> + <number>4</number> + </property> + <property name="segmentStyle"> + <enum>QLCDNumber::Outline</enum> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLCDNumber" name="raw_z"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="lineWidth"> + <number>1</number> + </property> + <property name="smallDecimalPoint"> + <bool>true</bool> + </property> + <property name="digitCount"> + <number>4</number> + </property> + <property name="segmentStyle"> + <enum>QLCDNumber::Outline</enum> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="lblX_4"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="text"> + <string>TX</string> + </property> + </widget> + </item> + <item row="1" column="3"> + <widget class="QLCDNumber" name="raw_pitch"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="lineWidth"> + <number>1</number> + </property> + <property name="smallDecimalPoint"> + <bool>true</bool> + </property> + <property name="digitCount"> + <number>4</number> + </property> + <property name="segmentStyle"> + <enum>QLCDNumber::Outline</enum> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="lblY_4"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="autoFillBackground"> + <bool>false</bool> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="text"> + <string>TY</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="box_mapped_headpose"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string notr="true">Game data</string> + </property> + <layout class="QGridLayout" name="gridLayout_14"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="horizontalSpacing"> + <number>3</number> + </property> + <property name="verticalSpacing"> + <number>2</number> + </property> + <item row="1" column="0"> + <widget class="QLabel" name="lblY_2"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="autoFillBackground"> + <bool>false</bool> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="text"> + <string>TY</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="lblZ_2"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="autoFillBackground"> + <bool>false</bool> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="text"> + <string>TZ</string> + </property> + </widget> + </item> + <item row="2" column="2"> + <widget class="QLabel" name="lblRotZ_2"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="text"> + <string>roll</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLCDNumber" name="pose_x"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="smallDecimalPoint"> + <bool>true</bool> + </property> + <property name="digitCount"> + <number>4</number> + </property> + <property name="segmentStyle"> + <enum>QLCDNumber::Flat</enum> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="lblRotX_2"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="text"> + <string>yaw</string> + </property> + </widget> + </item> + <item row="1" column="2"> + <widget class="QLabel" name="lblRotY_2"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="text"> + <string>pitch</string> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="lblx"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="text"> + <string>TX</string> + </property> + </widget> + </item> + <item row="1" column="3"> + <widget class="QLCDNumber" name="pose_pitch"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="smallDecimalPoint"> + <bool>true</bool> + </property> + <property name="digitCount"> + <number>4</number> + </property> + <property name="segmentStyle"> + <enum>QLCDNumber::Flat</enum> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLCDNumber" name="pose_y"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="smallDecimalPoint"> + <bool>true</bool> + </property> + <property name="digitCount"> + <number>4</number> + </property> + <property name="segmentStyle"> + <enum>QLCDNumber::Flat</enum> + </property> + </widget> + </item> + <item row="2" column="3"> + <widget class="QLCDNumber" name="pose_roll"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="smallDecimalPoint"> + <bool>true</bool> + </property> + <property name="digitCount"> + <number>4</number> + </property> + <property name="segmentStyle"> + <enum>QLCDNumber::Flat</enum> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLCDNumber" name="pose_z"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="smallDecimalPoint"> + <bool>true</bool> + </property> + <property name="digitCount"> + <number>4</number> + </property> + <property name="segmentStyle"> + <enum>QLCDNumber::Flat</enum> + </property> + </widget> + </item> + <item row="0" column="3"> + <widget class="QLCDNumber" name="pose_yaw"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="smallDecimalPoint"> + <bool>true</bool> + </property> + <property name="digitCount"> + <number>4</number> + </property> + <property name="segmentStyle"> + <enum>QLCDNumber::Flat</enum> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </item> + <item row="1" column="0"> + <widget class="QFrame" name="bottom_controls"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <layout class="QGridLayout" name="gridLayout_2"> + <property name="leftMargin"> + <number>4</number> + </property> + <property name="topMargin"> + <number>8</number> + </property> + <property name="rightMargin"> + <number>10</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="horizontalSpacing"> + <number>4</number> + </property> + <property name="verticalSpacing"> + <number>0</number> + </property> + <item row="1" column="1"> + <widget class="QGroupBox" name="groupWindows"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>4</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Settings</string> + </property> + <property name="flat"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <property name="spacing"> + <number>3</number> + </property> + <property name="leftMargin"> + <number>4</number> + </property> + <property name="topMargin"> + <number>2</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>6</number> + </property> + <item> + <widget class="QGroupBox" name="groupGameProtocol"> + <property name="title"> + <string>Protocol</string> + </property> + <layout class="QGridLayout" name="gridLayout_4"> + <property name="leftMargin"> + <number>4</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>4</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="horizontalSpacing"> + <number>3</number> + </property> + <property name="verticalSpacing"> + <number>0</number> + </property> + <item row="0" column="0"> + <widget class="QComboBox" name="iconcomboProtocol"/> + </item> + <item row="0" column="1"> + <widget class="QToolButton" name="btnShowServerControls"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>...</string> + </property> + <property name="flat" stdset="0"> + <bool>false</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QFrame" name="groupProfile"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding"> + <horstretch>0</horstretch> + <verstretch>2</verstretch> + </sizepolicy> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>2</number> + </property> + <property name="bottomMargin"> + <number>2</number> + </property> + <item> + <widget class="QToolButton" name="profile_button"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Profile</string> + </property> + <property name="popupMode"> + <enum>QToolButton::InstantPopup</enum> + </property> + <property name="toolButtonStyle"> + <enum>Qt::ToolButtonTextBesideIcon</enum> + </property> + <property name="autoRaise"> + <bool>true</bool> + </property> + <property name="arrowType"> + <enum>Qt::DownArrow</enum> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="iconcomboProfile"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maxVisibleItems"> + <number>20</number> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnEditCurves"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>3</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Mapping</string> + </property> + <property name="icon"> + <iconset resource="ui-res.qrc"> + <normaloff>:/images/curves.png</normaloff>:/images/curves.png</iconset> + </property> + <property name="iconSize"> + <size> + <width>80</width> + <height>24</height> + </size> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnShortcuts"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>3</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Options</string> + </property> + <property name="icon"> + <iconset resource="ui-res.qrc"> + <normaloff>:/images/tools.png</normaloff>:/images/tools.png</iconset> + </property> + <property name="iconSize"> + <size> + <width>80</width> + <height>24</height> + </size> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="1" column="0"> + <widget class="QGroupBox" name="groupStartStop"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>3</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string notr="true">Controls</string> + </property> + <property name="flat"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <property name="spacing"> + <number>8</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>8</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>9</number> + </property> + <item> + <widget class="QToolButton" name="btnStartTracker"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Start</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="btnStopTracker"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Stop</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </widget> + <customwidgets> + <customwidget> + <class>GLWidget</class> + <extends>QWidget</extends> + <header>pose-widget/glwidget.h</header> + </customwidget> + </customwidgets> + <tabstops> + <tabstop>btnStartTracker</tabstop> + <tabstop>btnStopTracker</tabstop> + <tabstop>iconcomboProtocol</tabstop> + <tabstop>btnShowServerControls</tabstop> + <tabstop>btnEditCurves</tabstop> + <tabstop>btnShortcuts</tabstop> + </tabstops> + <resources> + <include location="ui-res.qrc"/> + </resources> + <connections/> +</ui> diff --git a/gui/mapping.ui b/gui/mapping.ui new file mode 100644 index 00000000..75c32e27 --- /dev/null +++ b/gui/mapping.ui @@ -0,0 +1,391 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>UICCurveConfigurationDialog</class> + <widget class="QWidget" name="UICCurveConfigurationDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>970</width> + <height>664</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>970</width> + <height>664</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>970</width> + <height>664</height> + </size> + </property> + <property name="windowTitle"> + <string>Mapping properties</string> + </property> + <property name="windowIcon"> + <iconset> + <normaloff>images/facetracknoir.png</normaloff>images/facetracknoir.png</iconset> + </property> + <property name="layoutDirection"> + <enum>Qt::LeftToRight</enum> + </property> + <property name="styleSheet"> + <string notr="true">background-color: #ccc;</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QTabWidget" name="tabWidget"> + <property name="styleSheet"> + <string notr="true"/> + </property> + <property name="tabPosition"> + <enum>QTabWidget::North</enum> + </property> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="tabWidgetPage1"> + <attribute name="title"> + <string>Yaw</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QFunctionConfigurator" name="rxconfig" native="true"> + <property name="colorBezier" stdset="0"> + <color> + <red>255</red> + <green>0</green> + <blue>0</blue> + </color> + </property> + <property name="colorBackground" stdset="0"> + <color> + <red>240</red> + <green>240</green> + <blue>240</blue> + </color> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="rx_altp"> + <property name="text"> + <string>Asymmetric mapping below</string> + </property> + </widget> + </item> + <item> + <widget class="QFunctionConfigurator" name="rxconfig_alt" native="true"> + <property name="colorBezier" stdset="0"> + <color> + <red>255</red> + <green>0</green> + <blue>0</blue> + </color> + </property> + <property name="colorBackground" stdset="0"> + <color> + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="tabWidgetPage2"> + <attribute name="title"> + <string>Pitch</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <widget class="QFunctionConfigurator" name="ryconfig" native="true"> + <property name="colorBezier" stdset="0"> + <color> + <red>0</red> + <green>255</green> + <blue>0</blue> + </color> + </property> + <property name="colorBackground" stdset="0"> + <color> + <red>240</red> + <green>240</green> + <blue>240</blue> + </color> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="ry_altp"> + <property name="text"> + <string>Asymmetric mapping below</string> + </property> + </widget> + </item> + <item> + <widget class="QFunctionConfigurator" name="ryconfig_alt" native="true"> + <property name="colorBezier" stdset="0"> + <color> + <red>0</red> + <green>255</green> + <blue>0</blue> + </color> + </property> + <property name="colorBackground" stdset="0"> + <color> + <red>240</red> + <green>240</green> + <blue>240</blue> + </color> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="tabWidgetPage3"> + <attribute name="title"> + <string>Roll</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <item> + <widget class="QFunctionConfigurator" name="rzconfig" native="true"> + <property name="colorBezier" stdset="0"> + <color> + <red>0</red> + <green>0</green> + <blue>255</blue> + </color> + </property> + <property name="colorBackground" stdset="0"> + <color> + <red>240</red> + <green>240</green> + <blue>240</blue> + </color> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="rz_altp"> + <property name="text"> + <string>Asymmetric mapping below</string> + </property> + </widget> + </item> + <item> + <widget class="QFunctionConfigurator" name="rzconfig_alt" native="true"> + <property name="colorBezier" stdset="0"> + <color> + <red>0</red> + <green>0</green> + <blue>255</blue> + </color> + </property> + <property name="colorBackground" stdset="0"> + <color> + <red>240</red> + <green>240</green> + <blue>240</blue> + </color> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="tabWidgetPage4"> + <attribute name="title"> + <string>X</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_5"> + <item> + <widget class="QFunctionConfigurator" name="txconfig" native="true"> + <property name="colorBezier" stdset="0"> + <color> + <red>255</red> + <green>0</green> + <blue>255</blue> + </color> + </property> + <property name="colorBackground" stdset="0"> + <color> + <red>240</red> + <green>240</green> + <blue>240</blue> + </color> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="tx_altp"> + <property name="text"> + <string>Asymmetric mapping below</string> + </property> + </widget> + </item> + <item> + <widget class="QFunctionConfigurator" name="txconfig_alt" native="true"> + <property name="colorBezier" stdset="0"> + <color> + <red>255</red> + <green>0</green> + <blue>255</blue> + </color> + </property> + <property name="colorBackground" stdset="0"> + <color> + <red>240</red> + <green>240</green> + <blue>240</blue> + </color> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="tabWidgetPage5"> + <attribute name="title"> + <string>Y</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_6"> + <item> + <widget class="QFunctionConfigurator" name="tyconfig" native="true"> + <property name="colorBezier" stdset="0"> + <color> + <red>255</red> + <green>255</green> + <blue>0</blue> + </color> + </property> + <property name="colorBackground" stdset="0"> + <color> + <red>240</red> + <green>240</green> + <blue>240</blue> + </color> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="ty_altp"> + <property name="text"> + <string>Asymmetric mapping below</string> + </property> + </widget> + </item> + <item> + <widget class="QFunctionConfigurator" name="tyconfig_alt" native="true"> + <property name="colorBezier" stdset="0"> + <color> + <red>255</red> + <green>255</green> + <blue>0</blue> + </color> + </property> + <property name="colorBackground" stdset="0"> + <color> + <red>240</red> + <green>240</green> + <blue>240</blue> + </color> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="tabWidgetPage6"> + <attribute name="title"> + <string>Z</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_7"> + <item> + <widget class="QFunctionConfigurator" name="tzconfig" native="true"> + <property name="colorBezier" stdset="0"> + <color> + <red>0</red> + <green>255</green> + <blue>255</blue> + </color> + </property> + <property name="colorBackground" stdset="0"> + <color> + <red>240</red> + <green>240</green> + <blue>240</blue> + </color> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="tz_altp"> + <property name="text"> + <string>Asymmetric mapping below</string> + </property> + </widget> + </item> + <item> + <widget class="QFunctionConfigurator" name="tzconfig_alt" native="true"> + <property name="colorBezier" stdset="0"> + <color> + <red>0</red> + <green>255</green> + <blue>255</blue> + </color> + </property> + <property name="colorBackground" stdset="0"> + <color> + <red>240</red> + <green>240</green> + <blue>240</blue> + </color> + </property> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>QFunctionConfigurator</class> + <extends>QWidget</extends> + <header>spline-widget/qfunctionconfigurator.h</header> + </customwidget> + </customwidgets> + <tabstops> + <tabstop>ry_altp</tabstop> + <tabstop>rz_altp</tabstop> + <tabstop>tx_altp</tabstop> + <tabstop>ty_altp</tabstop> + <tabstop>tz_altp</tabstop> + <tabstop>tabWidget</tabstop> + <tabstop>buttonBox</tabstop> + <tabstop>rx_altp</tabstop> + </tabstops> + <resources/> + <connections/> + <slots> + <slot>startEngineClicked()</slot> + <slot>stopEngineClicked()</slot> + <slot>cameraSettingsClicked()</slot> + </slots> +</ui> diff --git a/gui/new_config.ui b/gui/new_config.ui new file mode 100644 index 00000000..27dce0f8 --- /dev/null +++ b/gui/new_config.ui @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>UI_new_config</class> + <widget class="QDialog" name="UI_new_config"> + <property name="windowModality"> + <enum>Qt::ApplicationModal</enum> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>269</width> + <height>67</height> + </rect> + </property> + <property name="windowTitle"> + <string>Config filename</string> + </property> + <property name="windowIcon"> + <iconset> + <normaloff>images/facetracknoir.png</normaloff>images/facetracknoir.png</iconset> + </property> + <layout class="QFormLayout" name="formLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>New file name:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="lineEdit"/> + </item> + <item row="1" column="1"> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/gui/new_file_dialog.h b/gui/new_file_dialog.h new file mode 100644 index 00000000..3a35cf71 --- /dev/null +++ b/gui/new_file_dialog.h @@ -0,0 +1,50 @@ +#pragma once + +#include "ui_new_config.h" +#include "opentrack/options.hpp" +#include <QFile> +#include <QRegExp> +#include <QString> +#include <QMessageBox> + +class new_file_dialog : public QDialog +{ + Q_OBJECT +public: + new_file_dialog(QWidget* parent = 0) : QDialog(parent), ok(false) + { + ui.setupUi(this); + connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(ok_clicked())); + connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(cancel_clicked())); + setFixedSize(size()); + } + bool is_ok(QString& name_) + { + name_ = name; + return ok; + } +private: + Ui::UI_new_config ui; + bool ok; + QString name; +private slots: + void cancel_clicked() { close(); } + void ok_clicked() + { + QString text = ui.lineEdit->text(); + text = text.replace('/', ""); + text = text.replace('\\', ""); + if (text != "" && !text.endsWith(".ini")) + text += ".ini"; + if (text == "" || text == ".ini" || QFile(options::group::ini_directory() + "/" + text).exists()) + { + QMessageBox::warning(this, + "File exists", "This file already exists. Pick another name.", + QMessageBox::Ok, QMessageBox::NoButton); + return; + } + ok = true; + close(); + name = text; + } +}; diff --git a/gui/options-dialog.cpp b/gui/options-dialog.cpp new file mode 100644 index 00000000..06346b25 --- /dev/null +++ b/gui/options-dialog.cpp @@ -0,0 +1,241 @@ +/* Copyright (c) 2015, Stanislaw Halik <sthalik@misaki.pl> + + * Permission to use, copy, modify, and/or distribute this + * software for any purpose with or without fee is hereby granted, + * provided that the above copyright notice and this permission + * notice appear in all copies. + */ + +#include "options-dialog.hpp" +#include "tracker-pt/camera.h" +#include "keyboard.h" +#include <QPushButton> +#include <QLayout> + +OptionsDialog::OptionsDialog(State& state) : state(state), trans_calib_running(false) +{ + ui.setupUi( this ); + + connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(doOK())); + connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(doCancel())); + + tie_setting(s.s_main.tray_enabled, ui.trayp); + + tie_setting(s.s_main.center_at_startup, ui.center_at_startup); + + tie_setting(s.s_main.tcomp_p, ui.tcomp_enable); + tie_setting(s.s_main.tcomp_tz, ui.tcomp_rz); + + tie_setting(s.s_main.a_yaw.invert, ui.invert_yaw); + tie_setting(s.s_main.a_pitch.invert, ui.invert_pitch); + tie_setting(s.s_main.a_roll.invert, ui.invert_roll); + tie_setting(s.s_main.a_x.invert, ui.invert_x); + tie_setting(s.s_main.a_y.invert, ui.invert_y); + tie_setting(s.s_main.a_z.invert, ui.invert_z); + + tie_setting(s.s_main.a_yaw.src, ui.src_yaw); + tie_setting(s.s_main.a_pitch.src, ui.src_pitch); + tie_setting(s.s_main.a_roll.src, ui.src_roll); + tie_setting(s.s_main.a_x.src, ui.src_x); + tie_setting(s.s_main.a_y.src, ui.src_y); + tie_setting(s.s_main.a_z.src, ui.src_z); + + tie_setting(s.s_main.camera_yaw, ui.camera_yaw); + tie_setting(s.s_main.camera_pitch, ui.camera_pitch); + tie_setting(s.s_main.camera_roll, ui.camera_roll); + + tie_setting(pt.camera_mode, ui.camera_mode); + + tie_setting(pt.threshold, ui.threshold_slider); + + tie_setting(pt.min_point_size, ui.mindiam_spin); + tie_setting(pt.max_point_size, ui.maxdiam_spin); + + tie_setting(pt.t_MH_x, ui.tx_spin); + tie_setting(pt.t_MH_y, ui.ty_spin); + tie_setting(pt.t_MH_z, ui.tz_spin); + + tie_setting(pt.fov, ui.camera_fov); + + tie_setting(pt.model_used, ui.model_used); + + connect(ui.ewma_slider, SIGNAL(valueChanged(int)), this, SLOT(update_ewma_display(int))); + connect(ui.rotation_slider, SIGNAL(valueChanged(int)), this, SLOT(update_rot_display(int))); + connect(ui.rot_dz_slider, SIGNAL(valueChanged(int)), this, SLOT(update_rot_dz_display(int))); + connect(ui.translation_slider, SIGNAL(valueChanged(int)), this, SLOT(update_trans_display(int))); + connect(ui.trans_dz_slider, SIGNAL(valueChanged(int)), this, SLOT(update_trans_dz_display(int))); + + tie_setting(acc.rot_threshold, ui.rotation_slider); + tie_setting(acc.trans_threshold, ui.translation_slider); + tie_setting(acc.ewma, ui.ewma_slider); + tie_setting(acc.rot_deadzone, ui.rot_dz_slider); + tie_setting(acc.trans_deadzone, ui.trans_dz_slider); + + update_rot_display(ui.rotation_slider->value()); + update_trans_display(ui.translation_slider->value()); + update_ewma_display(ui.ewma_slider->value()); + update_rot_dz_display(ui.rot_dz_slider->value()); + update_trans_dz_display(ui.trans_dz_slider->value()); + + tie_setting(pt.dynamic_pose, ui.dynamic_pose); + tie_setting(pt.init_phase_timeout, ui.init_phase_timeout); + tie_setting(pt.auto_threshold, ui.auto_threshold); + + connect(&timer,SIGNAL(timeout()), this,SLOT(poll_tracker_info())); + connect( ui.tcalib_button,SIGNAL(toggled(bool)), this,SLOT(startstop_trans_calib(bool)) ); + + timer.start(100); + + connect(ui.bind_center, &QPushButton::pressed, [&]() -> void { bind_key(s.center.keycode, ui.center_text); }); + connect(ui.bind_zero, &QPushButton::pressed, [&]() -> void { bind_key(s.zero.keycode, ui.zero_text); }); + connect(ui.bind_toggle, &QPushButton::pressed, [&]() -> void { bind_key(s.toggle.keycode, ui.toggle_text); }); + + ui.center_text->setText(s.center.keycode == "" ? "None" : static_cast<QString>(s.center.keycode)); + ui.toggle_text->setText(s.toggle.keycode == "" ? "None" : static_cast<QString>(s.toggle.keycode)); + ui.zero_text->setText(s.zero.keycode == "" ? "None" : static_cast<QString>(s.zero.keycode)); +} + +void OptionsDialog::bind_key(value<QString>& ret, QLabel* label) +{ + ret = ""; + QDialog d; + auto l = new QHBoxLayout; + l->setMargin(0); + auto k = new KeyboardListener; + l->addWidget(k); + d.setLayout(l); + d.setFixedSize(QSize(500, 300)); + d.setWindowFlags(Qt::Dialog); + connect(k, &KeyboardListener::key_pressed, [&] (QKeySequence s) -> void { ret = s.toString(QKeySequence::PortableText); d.close(); }); + d.exec(); + label->setText(ret == "" ? "None" : static_cast<QString>(ret)); + delete k; + delete l; +} + +void OptionsDialog::doOK() { + s.b->save(); + pt.b->save(); + s.s_main.b->save(); + acc.b->save(); + ui.game_detector->save(); + this->close(); + emit reload(); +} + +void OptionsDialog::doCancel() { + s.b->reload(); + pt.b->reload(); + s.s_main.b->reload(); + acc.b->reload(); + ui.game_detector->revert(); + close(); +} + +void OptionsDialog::startstop_trans_calib(bool start) +{ + auto tracker = get_pt(); + if (!tracker) + { + ui.tcalib_button->setChecked(false); + return; + } + + if (start) + { + qDebug()<<"TrackerDialog:: Starting translation calibration"; + trans_calib.reset(); + trans_calib_running = true; + pt.t_MH_x = 0; + pt.t_MH_y = 0; + pt.t_MH_z = 0; + } + else + { + qDebug()<<"TrackerDialog:: Stopping translation calibration"; + trans_calib_running = false; + { + auto tmp = trans_calib.get_estimate(); + pt.t_MH_x = tmp[0]; + pt.t_MH_y = tmp[1]; + pt.t_MH_z = tmp[2]; + } + } +} + +void OptionsDialog::poll_tracker_info() +{ + auto tracker = get_pt(); + CamInfo info; + if (tracker && tracker->get_cam_info(&info)) + { + QString to_print; + + // display caminfo + to_print = QString::number(info.res_x)+"x"+QString::number(info.res_y)+" @ "+QString::number(info.fps)+" FPS"; + ui.caminfo_label->setText(to_print); + + // display pointinfo + int n_points = tracker->get_n_points(); + to_print = QString::number(n_points); + if (n_points == 3) + to_print += " OK!"; + else + to_print += " BAD!"; + ui.pointinfo_label->setText(to_print); + + // update calibration + if (trans_calib_running) trans_calib_step(); + } + else + { + ui.caminfo_label->setText("Tracker offline"); + ui.pointinfo_label->setText(""); + } +} + +void OptionsDialog::trans_calib_step() +{ + auto tracker = get_pt(); + if (tracker) + { + Affine X_CM = tracker->pose(); + trans_calib.update(X_CM.R, X_CM.t); + } +} + +Tracker_PT* OptionsDialog::get_pt() +{ + auto work = state.work.get(); + if (!work) + return nullptr; + auto ptr = work->libs.pTracker; + if (ptr) + return static_cast<Tracker_PT*>(ptr.get()); + return nullptr; +} + +void OptionsDialog::update_rot_display(int value) +{ + ui.rot_gain->setText(QString::number((value + 1) * 10 / 100.) + "°"); +} + +void OptionsDialog::update_trans_display(int value) +{ + ui.trans_gain->setText(QString::number((value + 1) * 5 / 100.) + "mm"); +} + +void OptionsDialog::update_ewma_display(int value) +{ + ui.ewma_label->setText(QString::number(value * 2) + "ms"); +} + +void OptionsDialog::update_rot_dz_display(int value) +{ + ui.rot_dz->setText(QString::number(value * 2 / 100.) + "°"); +} + +void OptionsDialog::update_trans_dz_display(int value) +{ + ui.trans_dz->setText(QString::number(value * 1 / 100.) + "mm"); +} diff --git a/gui/options-dialog.hpp b/gui/options-dialog.hpp new file mode 100644 index 00000000..8fc16611 --- /dev/null +++ b/gui/options-dialog.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include <QObject> +#include <QWidget> +#include <QTimer> +#include "ui_settings.h" +#include "opentrack/state.hpp" +#include "opentrack/shortcuts.h" +#include "tracker-pt/ftnoir_tracker_pt_settings.h" +#include "trans_calib.h" +#include "tracker-pt/ftnoir_tracker_pt.h" +#include "filter-accela/ftnoir_filter_accela.h" + +class OptionsDialog: public QWidget +{ + Q_OBJECT +signals: + void reload(); +public: + OptionsDialog(State &state); +private: + Ui::UI_Settings ui; + Shortcuts::settings s; + settings_pt pt; + settings_accela acc; + QTimer timer; + State& state; + TranslationCalibrator trans_calib; + bool trans_calib_running; + + Tracker_PT* get_pt(); + void closeEvent(QCloseEvent *) override { doCancel(); } +private slots: + void update_ewma_display(int value); + void update_rot_display(int value); + void update_trans_display(int value); + void update_rot_dz_display(int value); + void update_trans_dz_display(int value); + + void doOK(); + void doCancel(); + void startstop_trans_calib(bool start); + void poll_tracker_info(); + void trans_calib_step(); + void bind_key(value<QString>& ret, QLabel* label); +}; diff --git a/gui/process_detector.cpp b/gui/process_detector.cpp new file mode 100644 index 00000000..f9fa4b59 --- /dev/null +++ b/gui/process_detector.cpp @@ -0,0 +1,211 @@ +/* Copyright (c) 2015, Stanislaw Halik <sthalik@misaki.pl> + + * Permission to use, copy, modify, and/or distribute this + * software for any purpose with or without fee is hereby granted, + * provided that the above copyright notice and this permission + * notice appear in all copies. + */ + +#include "process_detector.h" +#include "ui.h" +#include "opentrack-compat/process-list.hpp" +#include <QList> +#include <QFileDialog> +#include <QComboBox> +#include <QString> +#include <QHash> +#include <QPushButton> + +void settings::set_game_list(const QString &game_list) +{ + QSettings settings(OPENTRACK_ORG); + settings.setValue("executable-list", game_list); +} + +QString settings::get_game_list() +{ + QSettings settings(OPENTRACK_ORG); + return settings.value("executable-list").toString(); +} + +bool settings::is_enabled() +{ + QSettings settings(OPENTRACK_ORG); + return settings.value("executable-detector-enabled", false).toBool(); +} + +void settings::set_is_enabled(bool enabled) +{ + QSettings settings(OPENTRACK_ORG); + settings.setValue("executable-detector-enabled", enabled); +} + +QHash<QString, QString> settings::split_process_names() +{ + QHash<QString, QString> ret; + QString str = get_game_list(); + QStringList pairs = str.split('|'); + for (auto pair : pairs) + { + QList<QString> tmp = pair.split(':'); + if (tmp.count() != 2) + continue; + ret[tmp[0]] = tmp[1]; + } + return ret; +} + +void BrowseButton::browse() +{ + QFileDialog dialog(this); + dialog.setFileMode(QFileDialog::ExistingFile); + QString dir_path = QFileInfo(group::ini_pathname()).absolutePath(); + QString filename = dialog.getOpenFileName( + this, + tr("Set executable name"), + dir_path, + tr("Executable (*.exe);;All Files (*)")); + MainWindow::set_working_directory(); + filename = QFileInfo(filename).fileName(); + if (!filename.isNull()) + twi->setText(filename); +} + +int process_detector::add_row(QString exe_name, QString profile) +{ + int i = ui.tableWidget->rowCount(); + ui.tableWidget->insertRow(i); + + QComboBox* cb = new QComboBox(); + cb->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Maximum); + cb->addItem(""); + cb->addItems(group::ini_list()); + ui.tableWidget->setCellWidget(i, 1, cb); + + QTableWidgetItem* twi = new QTableWidgetItem(exe_name); + ui.tableWidget->setItem(i, 0, twi); + + { + BrowseButton* b = new BrowseButton(twi); + b->setText("..."); + QObject::connect(b, SIGNAL(pressed()), b, SLOT(browse())); + ui.tableWidget->setCellWidget(i, 2, b); + } + + cb->setCurrentText(profile); + + return i; +} + +void process_detector::add_items() +{ + auto names = s.split_process_names(); + ui.tableWidget->clearContents(); + auto keys = names.keys(); + qSort(keys); + for (auto n : keys) + add_row(n, names[n]); +} + +process_detector::process_detector(QWidget* parent) : QWidget(parent) +{ + ui.setupUi(this); + setFixedSize(size()); + connect(ui.add, SIGNAL(pressed()), this, SLOT(add())); + connect(ui.remove, SIGNAL(pressed()), this, SLOT(remove())); + + add_items(); + + QResizeEvent e(ui.tableWidget->size(), ui.tableWidget->size()); + ui.tableWidget->resizeEvent(&e); + + settings s; + + ui.enabled->setChecked(s.is_enabled()); +} + +void process_detector::save() +{ + QString str; + + for (int i = 0; i < ui.tableWidget->rowCount(); i++) + { + auto exe = ui.tableWidget->item(i, 0)->text(); + auto profile = reinterpret_cast<QComboBox*>(ui.tableWidget->cellWidget(i, 1))->currentText(); + str += "|" + exe + ":" + profile; + } + + s.set_game_list(str); + s.set_is_enabled(ui.enabled->isChecked()); +} + +void process_detector::revert() +{ +} + +void process_detector::add() +{ + add_row(); +} + +void process_detector::remove() +{ + int r = ui.tableWidget->currentRow(); + if (r != -1) + ui.tableWidget->removeRow(r); +} + +bool process_detector_worker::should_stop() +{ + if (last_exe_name == "") + return false; + + settings s; + + if (!s.is_enabled()) + { + last_exe_name = ""; + return false; + } + + QStringList exe_list = get_all_executable_names(); + + if (exe_list.contains(last_exe_name)) + return false; + + last_exe_name = ""; + + return true; +} + +bool process_detector_worker::config_to_start(QString& str) +{ + settings s; + if (!s.is_enabled()) + { + last_exe_name = ""; + return false; + } + + auto filenames = s.split_process_names(); + QStringList exe_list = get_all_executable_names(); + + // assuming manual stop by user button click. + // don't automatically start again while the same process is running. + if (last_exe_name != "" && exe_list.contains(last_exe_name)) + return false; + // it's gone, we can start automatically again + last_exe_name = ""; + + for (auto& name : exe_list) + { + if (filenames.contains(name)) + { + last_exe_name = name; + str = filenames[name]; + return str != ""; + } + } + + return false; +} diff --git a/gui/process_detector.h b/gui/process_detector.h new file mode 100644 index 00000000..f6497c90 --- /dev/null +++ b/gui/process_detector.h @@ -0,0 +1,86 @@ +/* Copyright (c) 2015, Stanislaw Halik <sthalik@misaki.pl> + + * Permission to use, copy, modify, and/or distribute this + * software for any purpose with or without fee is hereby granted, + * provided that the above copyright notice and this permission + * notice appear in all copies. + */ + +#pragma once + +#include <QObject> +#include <QWidget> +#include <QTableWidget> +#include <QResizeEvent> + +#include "opentrack/options.hpp" +using namespace options; + +class FancyTable : public QTableWidget +{ + Q_OBJECT +public: + void resizeEvent(QResizeEvent* e) override + { + QTableView::resizeEvent(e); + int w = width(); + setColumnWidth(2, 32); + w -= 48; + setColumnWidth(0, w / 2); + setColumnWidth(1, w / 2); + } +public: + FancyTable(QWidget* parent = nullptr) : QTableWidget(parent) {} +}; + +struct settings +{ + QHash<QString, QString> split_process_names(); + QString get_game_list(); + void set_game_list(const QString& game_list); + bool is_enabled(); + void set_is_enabled(bool enabled); +}; + +#include "ui_process_widget.h" + +class process_detector : public QWidget +{ + Q_OBJECT + + Ui_Dialog ui; + settings s; + + int add_row(QString exe_name = "...", QString profile = ""); + void add_items(); +public: + process_detector(QWidget* parent = nullptr); +public slots: + void save(); + void revert(); +private slots: + void add(); + void remove(); +}; + +class BrowseButton : public QPushButton +{ + Q_OBJECT + QTableWidgetItem* twi; +public: + BrowseButton(QTableWidgetItem* twi) : twi(twi) + {} +public slots: + void browse(); +}; + +class process_detector_worker : QObject +{ + Q_OBJECT + settings s; + QString last_exe_name; +public: + bool config_to_start(QString& s); + bool should_stop(); +}; + diff --git a/gui/process_widget.ui b/gui/process_widget.ui new file mode 100644 index 00000000..63ad9472 --- /dev/null +++ b/gui/process_widget.ui @@ -0,0 +1,121 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Dialog</class> + <widget class="QWidget" name="Dialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>302</width> + <height>325</height> + </rect> + </property> + <property name="windowTitle"> + <string>Game detector</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="FancyTable" name="tableWidget"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <column> + <property name="text"> + <string>Executable</string> + </property> + </column> + <column> + <property name="text"> + <string>Profile</string> + </property> + </column> + <column> + <property name="text"> + <string/> + </property> + </column> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="styleSheet"> + <string notr="true">border: 0;</string> + </property> + <property name="title"> + <string/> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="topMargin"> + <number>5</number> + </property> + <item> + <widget class="QPushButton" name="add"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="font"> + <font> + <pointsize>14</pointsize> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>+</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="remove"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="font"> + <font> + <pointsize>14</pointsize> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>-</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QCheckBox" name="enabled"> + <property name="text"> + <string>Start profiles from game executable names in this list</string> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>FancyTable</class> + <extends>QTableWidget</extends> + <header>process_detector.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/gui/settings.ui b/gui/settings.ui new file mode 100644 index 00000000..5bf819fd --- /dev/null +++ b/gui/settings.ui @@ -0,0 +1,1721 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>UI_Settings</class> + <widget class="QWidget" name="UI_Settings"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>428</width> + <height>535</height> + </rect> + </property> + <property name="windowTitle"> + <string>Options</string> + </property> + <property name="windowIcon"> + <iconset> + <normaloff>images/facetracknoir.png</normaloff>images/facetracknoir.png</iconset> + </property> + <property name="layoutDirection"> + <enum>Qt::LeftToRight</enum> + </property> + <property name="autoFillBackground"> + <bool>false</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QTabWidget" name="tabWidget"> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="tab"> + <attribute name="title"> + <string>Shortcuts</string> + </attribute> + <layout class="QGridLayout" name="gridLayout_9"> + <item row="0" column="0"> + <widget class="QGroupBox" name="groupBox_8"> + <property name="title"> + <string>Global shortcuts</string> + </property> + <layout class="QGridLayout" name="gridLayout_15"> + <item row="0" column="0"> + <widget class="QLabel" name="label_23"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string><html><head/><body><p><span style=" font-weight:600;">Center</span> - use current pose as looking perfectly forward.<br/><span style=" font-weight:600;">Toggle</span> - keep looking at same spot until toggle keypress.<br/><span style=" font-weight:600;">Zero</span> - keep looking forward while the key is pressed.<br/></p></body></html></string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QGroupBox" name="groupBox"> + <property name="styleSheet"> + <string notr="true">QGroupBox { border: 0; }</string> + </property> + <layout class="QGridLayout" name="gridLayout_8"> + <item row="0" column="1"> + <widget class="QLabel" name="center_text"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="textLabel2_3"> + <property name="text"> + <string>Center</string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="6" column="1"> + <widget class="QLabel" name="zero_text"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="5" column="1"> + <widget class="QLabel" name="toggle_text"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="5" column="0"> + <widget class="QLabel" name="textLabel2_5"> + <property name="text"> + <string>Toggle</string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="6" column="0"> + <widget class="QLabel" name="textLabel2_6"> + <property name="text"> + <string>Zero</string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QPushButton" name="bind_center"> + <property name="text"> + <string>Bind</string> + </property> + </widget> + </item> + <item row="5" column="2"> + <widget class="QPushButton" name="bind_toggle"> + <property name="text"> + <string>Bind</string> + </property> + </widget> + </item> + <item row="6" column="2"> + <widget class="QPushButton" name="bind_zero"> + <property name="text"> + <string>Bind</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </item> + <item row="1" column="0"> + <widget class="QCheckBox" name="center_at_startup"> + <property name="text"> + <string>Center at startup</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QCheckBox" name="trayp"> + <property name="text"> + <string>Minimize to tray</string> + </property> + </widget> + </item> + <item row="3" column="0"> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_3"> + <attribute name="title"> + <string>Camera</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_10"> + <item> + <widget class="QGroupBox" name="groupBox_9"> + <property name="title"> + <string>Device</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="2" column="0"> + <widget class="QLabel" name="label_32"> + <property name="text"> + <string>Dynamic pose resolution</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QCheckBox" name="dynamic_pose"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QComboBox" name="camera_mode"> + <item> + <property name="text"> + <string>640x480, 75 Hz</string> + </property> + </item> + <item> + <property name="text"> + <string>640x480, 60 Hz</string> + </property> + </item> + <item> + <property name="text"> + <string>320x240, 189 Hz</string> + </property> + </item> + <item> + <property name="text"> + <string>320x240, 120 Hz</string> + </property> + </item> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="label_2511"> + <property name="text"> + <string>Mode</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="camera_fov"> + <item> + <property name="text"> + <string>56°</string> + </property> + </item> + <item> + <property name="text"> + <string>75°</string> + </property> + </item> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Field of view</string> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_33"> + <property name="text"> + <string>Dynamic pose timeout</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QSpinBox" name="init_phase_timeout"> + <property name="suffix"> + <string> ms</string> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>10000</number> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox_6"> + <property name="title"> + <string>Point extraction</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <property name="topMargin"> + <number>4</number> + </property> + <property name="bottomMargin"> + <number>4</number> + </property> + <item> + <widget class="QFrame" name="frame_2"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <layout class="QGridLayout" name="gridLayout_10"> + <property name="topMargin"> + <number>2</number> + </property> + <property name="bottomMargin"> + <number>2</number> + </property> + <property name="verticalSpacing"> + <number>6</number> + </property> + <item row="1" column="1"> + <widget class="QSlider" name="threshold_slider"> + <property name="toolTip"> + <string>Intensity threshold for point extraction</string> + </property> + <property name="maximum"> + <number>255</number> + </property> + <property name="pageStep"> + <number>1</number> + </property> + <property name="value"> + <number>127</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="tickPosition"> + <enum>QSlider::TicksBothSides</enum> + </property> + <property name="tickInterval"> + <number>25</number> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Threshold</string> + </property> + <property name="buddy"> + <cstring>threshold_slider</cstring> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="label_38"> + <property name="text"> + <string>Automatic threshold</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QCheckBox" name="auto_threshold"> + <property name="text"> + <string>Enable, slider sets point size</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QFrame" name="frame"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QGridLayout" name="gridLayout_3"> + <property name="topMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="verticalSpacing"> + <number>0</number> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="label_29"> + <property name="text"> + <string>Min size</string> + </property> + <property name="buddy"> + <cstring>mindiam_spin</cstring> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="label_22"> + <property name="text"> + <string>Max size</string> + </property> + <property name="buddy"> + <cstring>maxdiam_spin</cstring> + </property> + </widget> + </item> + <item row="0" column="3"> + <widget class="QDoubleSpinBox" name="maxdiam_spin"> + <property name="toolTip"> + <string>Maximum point diameter</string> + </property> + <property name="suffix"> + <string> px</string> + </property> + <property name="decimals"> + <number>1</number> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QDoubleSpinBox" name="mindiam_spin"> + <property name="toolTip"> + <string>Minimum point diameter</string> + </property> + <property name="suffix"> + <string> px</string> + </property> + <property name="decimals"> + <number>1</number> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox_11"> + <property name="title"> + <string>Status</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="caminfo_label"> + <property name="text"> + <string>Not running</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="pointinfo_label"> + <property name="text"> + <string/> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_2"> + <attribute name="title"> + <string>Model</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QGroupBox" name="groupBox_6111"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="styleSheet"> + <string notr="true">QFrame { border: 0; }</string> + </property> + <layout class="QGridLayout" name="gridLayout_17"> + <property name="leftMargin"> + <number>31</number> + </property> + <property name="topMargin"> + <number>4</number> + </property> + <item row="0" column="1"> + <widget class="QComboBox" name="model_used"> + <property name="sizeAdjustPolicy"> + <enum>QComboBox::AdjustToMinimumContentsLength</enum> + </property> + <property name="iconSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <item> + <property name="text"> + <string>Cap</string> + </property> + <property name="icon"> + <iconset resource="ui-res.qrc"> + <normaloff>:/images/trackhat-hat.png</normaloff>:/images/trackhat-hat.png</iconset> + </property> + </item> + <item> + <property name="text"> + <string>Clip</string> + </property> + <property name="icon"> + <iconset resource="ui-res.qrc"> + <normaloff>:/images/trackhat-clip-right.png</normaloff>:/images/trackhat-clip-right.png</iconset> + </property> + </item> + <item> + <property name="text"> + <string>Clip left-handed</string> + </property> + <property name="icon"> + <iconset resource="ui-res.qrc"> + <normaloff>:/images/trackhat-clip-left.png</normaloff>:/images/trackhat-clip-left.png</iconset> + </property> + </item> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="label_31"> + <property name="text"> + <string>Model used</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox_10"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Model position calibration</string> + </property> + <layout class="QGridLayout" name="gridLayout_11"> + <item row="0" column="0"> + <widget class="QFrame" name="frame_3"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QGridLayout" name="gridLayout_12"> + <item row="0" column="0"> + <widget class="QLabel" name="label_61"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>x:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QSpinBox" name="tx_spin"> + <property name="suffix"> + <string> mm</string> + </property> + <property name="minimum"> + <number>-65535</number> + </property> + <property name="maximum"> + <number>65536</number> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_62"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>y:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QSpinBox" name="ty_spin"> + <property name="suffix"> + <string> mm</string> + </property> + <property name="minimum"> + <number>-65535</number> + </property> + <property name="maximum"> + <number>65536</number> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_66"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>z:</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QSpinBox" name="tz_spin"> + <property name="suffix"> + <string> mm</string> + </property> + <property name="minimum"> + <number>-65535</number> + </property> + <property name="maximum"> + <number>65536</number> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLabel" name="label_59"> + <property name="text"> + <string><html><head/><body><p>Only pitch and yaw during calibration.</p><p>Don't roll and don't translate.</p></body></html></string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QPushButton" name="tcalib_button"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Toggle calibration</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox_5"> + <property name="title"> + <string>Camera offset</string> + </property> + <layout class="QGridLayout" name="gridLayout_6"> + <item row="2" column="0"> + <widget class="QLabel" name="label_17"> + <property name="text"> + <string><html><head/><body><p>Specify an angle for off-center camera as a basis for which direction is which, avoiding axis interconnect. Also see <a href="https://github.com/opentrack/opentrack/wiki/choosing-camera-offset"><span style=" text-decoration: underline; color:#0000ff;">description on wiki</span></a>.</p></body></html></string> + </property> + <property name="alignment"> + <set>Qt::AlignJustify|Qt::AlignVCenter</set> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + <property name="margin"> + <number>2</number> + </property> + <property name="openExternalLinks"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="3" column="0" alignment="Qt::AlignLeft"> + <widget class="QGroupBox" name="groupBox_3"> + <property name="styleSheet"> + <string notr="true">QGroupBox +{ + border: 0; +}</string> + </property> + <layout class="QGridLayout" name="gridLayout_7"> + <item row="2" column="0"> + <widget class="QLabel" name="label_21"> + <property name="text"> + <string>Roll</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QSpinBox" name="camera_roll"> + <property name="minimumSize"> + <size> + <width>80</width> + <height>0</height> + </size> + </property> + <property name="minimum"> + <number>-180</number> + </property> + <property name="maximum"> + <number>180</number> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QSpinBox" name="camera_yaw"> + <property name="minimumSize"> + <size> + <width>80</width> + <height>0</height> + </size> + </property> + <property name="minimum"> + <number>-180</number> + </property> + <property name="maximum"> + <number>180</number> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_19"> + <property name="text"> + <string>Pitch</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QSpinBox" name="camera_pitch"> + <property name="minimumSize"> + <size> + <width>80</width> + <height>0</height> + </size> + </property> + <property name="minimum"> + <number>-180</number> + </property> + <property name="maximum"> + <number>180</number> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="label_18"> + <property name="text"> + <string>Yaw</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="verticalSpacer_5"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>10</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_4"> + <attribute name="title"> + <string>Output</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <item> + <widget class="QGroupBox" name="groupBox_"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="styleSheet"> + <string notr="true"/> + </property> + <property name="title"> + <string>Translation compensation</string> + </property> + <property name="flat"> + <bool>false</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout_7"> + <item> + <widget class="QLabel" name="label_16"> + <property name="text"> + <string>With compensation on, translation is applied after rotation. For example, rotating +180 degrees yaw and moving backwards results in moving forward as a result of that rotation.</string> + </property> + <property name="alignment"> + <set>Qt::AlignJustify|Qt::AlignVCenter</set> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + <property name="margin"> + <number>2</number> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="tcomp_enable"> + <property name="styleSheet"> + <string notr="true"/> + </property> + <property name="text"> + <string>Enable</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="tcomp_rz"> + <property name="styleSheet"> + <string notr="true"/> + </property> + <property name="text"> + <string>Disable Z axis compensation</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox_4"> + <property name="maximumSize"> + <size> + <width>65536</width> + <height>65536</height> + </size> + </property> + <property name="font"> + <font> + <kerning>true</kerning> + </font> + </property> + <property name="title"> + <string>Output remap</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="flat"> + <bool>false</bool> + </property> + <property name="checkable"> + <bool>false</bool> + </property> + <layout class="QGridLayout" name="gridLayout_4" rowstretch="0,0" columnstretch="0"> + <property name="sizeConstraint"> + <enum>QLayout::SetMinAndMaxSize</enum> + </property> + <property name="spacing"> + <number>6</number> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="label_20"> + <property name="text"> + <string>Assign input axis to output axis.</string> + </property> + <property name="alignment"> + <set>Qt::AlignJustify|Qt::AlignVCenter</set> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QGroupBox" name="groupBox_2"> + <property name="styleSheet"> + <string notr="true">QGroupBox +{ + border: 0; +}</string> + </property> + <layout class="QGridLayout" name="gridLayout_5"> + <item row="7" column="2"> + <widget class="QCheckBox" name="invert_y"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="5" column="0"> + <widget class="QLabel" name="label_9"> + <property name="text"> + <string>Roll</string> + </property> + </widget> + </item> + <item row="6" column="0"> + <widget class="QLabel" name="label_10"> + <property name="text"> + <string>X</string> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="label_14"> + <property name="text"> + <string>Invert</string> + </property> + </widget> + </item> + <item row="6" column="1"> + <widget class="QComboBox" name="src_x"> + <item> + <property name="text"> + <string>X</string> + </property> + </item> + <item> + <property name="text"> + <string>Y</string> + </property> + </item> + <item> + <property name="text"> + <string>Z</string> + </property> + </item> + <item> + <property name="text"> + <string>Yaw</string> + </property> + </item> + <item> + <property name="text"> + <string>Pitch</string> + </property> + </item> + <item> + <property name="text"> + <string>Roll</string> + </property> + </item> + <item> + <property name="text"> + <string>Disabled</string> + </property> + </item> + </widget> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="label_8"> + <property name="text"> + <string>Pitch</string> + </property> + </widget> + </item> + <item row="7" column="1"> + <widget class="QComboBox" name="src_y"> + <item> + <property name="text"> + <string>X</string> + </property> + </item> + <item> + <property name="text"> + <string>Y</string> + </property> + </item> + <item> + <property name="text"> + <string>Z</string> + </property> + </item> + <item> + <property name="text"> + <string>Yaw</string> + </property> + </item> + <item> + <property name="text"> + <string>Pitch</string> + </property> + </item> + <item> + <property name="text"> + <string>Roll</string> + </property> + </item> + <item> + <property name="text"> + <string>Disabled</string> + </property> + </item> + </widget> + </item> + <item row="3" column="1"> + <widget class="QComboBox" name="src_yaw"> + <item> + <property name="text"> + <string>X</string> + </property> + </item> + <item> + <property name="text"> + <string>Y</string> + </property> + </item> + <item> + <property name="text"> + <string>Z</string> + </property> + </item> + <item> + <property name="text"> + <string>Yaw</string> + </property> + </item> + <item> + <property name="text"> + <string>Pitch</string> + </property> + </item> + <item> + <property name="text"> + <string>Roll</string> + </property> + </item> + <item> + <property name="text"> + <string>Disabled</string> + </property> + </item> + </widget> + </item> + <item row="5" column="2"> + <widget class="QCheckBox" name="invert_roll"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="7" column="0"> + <widget class="QLabel" name="label_11"> + <property name="text"> + <string>Y</string> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="label_15"> + <property name="text"> + <string>Destination</string> + </property> + </widget> + </item> + <item row="4" column="2"> + <widget class="QCheckBox" name="invert_pitch"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_7"> + <property name="text"> + <string>Yaw</string> + </property> + </widget> + </item> + <item row="6" column="2"> + <widget class="QCheckBox" name="invert_x"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLabel" name="label_13"> + <property name="text"> + <string>Source</string> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QComboBox" name="src_pitch"> + <item> + <property name="text"> + <string>X</string> + </property> + </item> + <item> + <property name="text"> + <string>Y</string> + </property> + </item> + <item> + <property name="text"> + <string>Z</string> + </property> + </item> + <item> + <property name="text"> + <string>Yaw</string> + </property> + </item> + <item> + <property name="text"> + <string>Pitch</string> + </property> + </item> + <item> + <property name="text"> + <string>Roll</string> + </property> + </item> + <item> + <property name="text"> + <string>Disabled</string> + </property> + </item> + </widget> + </item> + <item row="3" column="2"> + <widget class="QCheckBox" name="invert_yaw"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="5" column="1"> + <widget class="QComboBox" name="src_roll"> + <item> + <property name="text"> + <string>X</string> + </property> + </item> + <item> + <property name="text"> + <string>Y</string> + </property> + </item> + <item> + <property name="text"> + <string>Z</string> + </property> + </item> + <item> + <property name="text"> + <string>Yaw</string> + </property> + </item> + <item> + <property name="text"> + <string>Pitch</string> + </property> + </item> + <item> + <property name="text"> + <string>Roll</string> + </property> + </item> + <item> + <property name="text"> + <string>Disabled</string> + </property> + </item> + </widget> + </item> + <item row="8" column="0"> + <widget class="QLabel" name="label_12"> + <property name="text"> + <string>Z</string> + </property> + </widget> + </item> + <item row="8" column="1"> + <widget class="QComboBox" name="src_z"> + <item> + <property name="text"> + <string>X</string> + </property> + </item> + <item> + <property name="text"> + <string>Y</string> + </property> + </item> + <item> + <property name="text"> + <string>Z</string> + </property> + </item> + <item> + <property name="text"> + <string>Yaw</string> + </property> + </item> + <item> + <property name="text"> + <string>Pitch</string> + </property> + </item> + <item> + <property name="text"> + <string>Roll</string> + </property> + </item> + <item> + <property name="text"> + <string>Disabled</string> + </property> + </item> + </widget> + </item> + <item row="8" column="2"> + <widget class="QCheckBox" name="invert_z"> + <property name="text"> + <string/> + </property> + </widget> + </item> + </layout> + <zorder>label_15</zorder> + <zorder>label_13</zorder> + <zorder>label_14</zorder> + <zorder>src_yaw</zorder> + <zorder>invert_yaw</zorder> + <zorder>label_7</zorder> + <zorder>src_pitch</zorder> + <zorder>label_8</zorder> + <zorder>invert_pitch</zorder> + <zorder>label_9</zorder> + <zorder>src_roll</zorder> + <zorder>invert_roll</zorder> + <zorder>label_10</zorder> + <zorder>src_x</zorder> + <zorder>invert_x</zorder> + <zorder>label_11</zorder> + <zorder>src_y</zorder> + <zorder>invert_y</zorder> + <zorder>label_12</zorder> + <zorder>src_z</zorder> + <zorder>invert_z</zorder> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="verticalSpacer_3"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_6"> + <attribute name="title"> + <string>Filter</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_6"> + <item> + <widget class="QFrame" name="frame_4"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QGridLayout" name="gridLayout_14"> + <item row="1" column="3"> + <widget class="QSlider" name="rotation_slider"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>24</height> + </size> + </property> + <property name="maximum"> + <number>99</number> + </property> + <property name="pageStep"> + <number>5</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="tickPosition"> + <enum>QSlider::TicksAbove</enum> + </property> + <property name="tickInterval"> + <number>24</number> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="lblSensYaw_6"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Rotation sensitivity</string> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="label_6"> + <property name="text"> + <string>Smoothing</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLabel" name="ewma_label"> + <property name="minimumSize"> + <size> + <width>48</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>0 ms</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLabel" name="rot_gain"> + <property name="text"> + <string>0°</string> + </property> + </widget> + </item> + <item row="0" column="3"> + <widget class="QSlider" name="ewma_slider"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>24</height> + </size> + </property> + <property name="maximum"> + <number>100</number> + </property> + <property name="singleStep"> + <number>10</number> + </property> + <property name="pageStep"> + <number>25</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="tickPosition"> + <enum>QSlider::TicksAbove</enum> + </property> + <property name="tickInterval"> + <number>24</number> + </property> + </widget> + </item> + <item row="6" column="0"> + <widget class="QLabel" name="label_27"> + <property name="text"> + <string>Translation deadzone</string> + </property> + </widget> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="label_28"> + <property name="text"> + <string>Rotation deadzone</string> + </property> + </widget> + </item> + <item row="4" column="3"> + <widget class="QSlider" name="rot_dz_slider"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>24</height> + </size> + </property> + <property name="maximum"> + <number>100</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="tickPosition"> + <enum>QSlider::TicksAbove</enum> + </property> + <property name="tickInterval"> + <number>24</number> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QLabel" name="rot_dz"> + <property name="text"> + <string>0°</string> + </property> + </widget> + </item> + <item row="6" column="3"> + <widget class="QSlider" name="trans_dz_slider"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>24</height> + </size> + </property> + <property name="maximum"> + <number>100</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="tickPosition"> + <enum>QSlider::TicksAbove</enum> + </property> + <property name="tickInterval"> + <number>24</number> + </property> + </widget> + </item> + <item row="6" column="1"> + <widget class="QLabel" name="trans_dz"> + <property name="text"> + <string>0mm</string> + </property> + </widget> + </item> + <item row="5" column="0"> + <widget class="QLabel" name="label_30"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Translation sensitivity</string> + </property> + </widget> + </item> + <item row="5" column="1"> + <widget class="QLabel" name="trans_gain"> + <property name="text"> + <string>0mm</string> + </property> + </widget> + </item> + <item row="5" column="3"> + <widget class="QSlider" name="translation_slider"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>24</height> + </size> + </property> + <property name="maximum"> + <number>99</number> + </property> + <property name="pageStep"> + <number>5</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="tickPosition"> + <enum>QSlider::TicksAbove</enum> + </property> + <property name="tickInterval"> + <number>24</number> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox_12"> + <property name="title"> + <string/> + </property> + <layout class="QGridLayout" name="gridLayout_13"> + <item row="0" column="1"> + <widget class="QLabel" name="label_26111"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="font"> + <font> + <pointsize>7</pointsize> + </font> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="text"> + <string><html><head/><body><p align="justify"><br/><span style=" font-size:10pt;">Accela by </span><a href="https://github.com/sthalik"><span style=" font-size:10pt; text-decoration: underline; color:#0057ae;">Stanisław Halik</span></a><span style=" font-size:10pt;"><br/>Thanks to </span><a href="https://github.com/dbaarda"><span style=" font-size:10pt; text-decoration: underline; color:#0057ae;">Donovan Baarda</span></a></p><p align="right"><span style=" font-size:10pt;">2012-2015</span></p></body></html></string> + </property> + <property name="textFormat"> + <enum>Qt::RichText</enum> + </property> + <property name="scaledContents"> + <bool>false</bool> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="indent"> + <number>0</number> + </property> + <property name="openExternalLinks"> + <bool>true</bool> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="label_5"> + <property name="text"> + <string><html><head/><body><p>Visit <a href="https://github.com/opentrack/opentrack/wiki/Accela-in-opentrack-2.3"><span style=" text-decoration: underline; color:#0000ff;">our wiki</span></a> for description of the settings.</p></body></html></string> + </property> + <property name="openExternalLinks"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="verticalSpacer_4"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_5"> + <attribute name="title"> + <string>Game detection</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_9"> + <item> + <widget class="QGroupBox" name="groupBox_1"> + <property name="title"> + <string>Game detection</string> + </property> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="0" column="0"> + <widget class="QLabel" name="label_24"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Start tracking automatically when a game starts with selected profile, and stop when the game exits.</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="process_detector" name="game_detector" native="true"/> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>process_detector</class> + <extends>QWidget</extends> + <header>process_detector.h</header> + </customwidget> + </customwidgets> + <tabstops> + <tabstop>tabWidget</tabstop> + <tabstop>center_at_startup</tabstop> + <tabstop>trayp</tabstop> + <tabstop>tcomp_enable</tabstop> + <tabstop>tcomp_rz</tabstop> + <tabstop>src_yaw</tabstop> + <tabstop>invert_yaw</tabstop> + <tabstop>src_pitch</tabstop> + <tabstop>invert_pitch</tabstop> + <tabstop>src_roll</tabstop> + <tabstop>invert_roll</tabstop> + <tabstop>src_x</tabstop> + <tabstop>invert_x</tabstop> + <tabstop>src_y</tabstop> + <tabstop>invert_y</tabstop> + <tabstop>src_z</tabstop> + <tabstop>invert_z</tabstop> + </tabstops> + <resources> + <include location="ui-res.qrc"/> + </resources> + <connections/> + <designerdata> + <property name="gridDeltaX"> + <number>5</number> + </property> + <property name="gridDeltaY"> + <number>5</number> + </property> + <property name="gridSnapX"> + <bool>true</bool> + </property> + <property name="gridSnapY"> + <bool>true</bool> + </property> + <property name="gridVisible"> + <bool>true</bool> + </property> + </designerdata> + <slots> + <slot>startEngineClicked()</slot> + <slot>stopEngineClicked()</slot> + <slot>cameraSettingsClicked()</slot> + </slots> +</ui> diff --git a/gui/software-update-dialog.hpp b/gui/software-update-dialog.hpp new file mode 100644 index 00000000..fe132402 --- /dev/null +++ b/gui/software-update-dialog.hpp @@ -0,0 +1,87 @@ +#pragma once + +#include <QtNetwork> +#include <QDialog> +#include <QSettings> +#include <QString> +#include <QRegExp> +#include <functional> +#include "ui_software-update.h" +#include "opentrack/options.hpp" + +extern "C" const char* opentrack_version; + +class update_dialog : public QDialog +{ + Q_OBJECT +public: + struct query + { + query(QWidget* parent) : parent(parent), qnam(parent) {} + + QWidget* parent; + QNetworkAccessManager qnam; + QByteArray buf; + QNetworkReply* r; + void on_finished() + { + if (r->error() != QNetworkReply::NoError) + { + qDebug() << "update error" << r->errorString(); + return; + } + QString str(buf); + QRegExp re("OPENTRACK_VERSION([a-zA-Z0-9_.-]+)"); + int idx = re.indexIn(str); + if (idx != -1) + { + str = re.cap(1); + QSettings s(OPENTRACK_ORG); + QString quiet_version = s.value("quiet-update-version").toString(); + + if (!str.isEmpty() && str != opentrack_version && str != quiet_version) + { + qDebug() << "update version" << str; + update_dialog dlg(parent, *this, str); + dlg.show(); + dlg.raise(); + dlg.exec(); + if (dlg.ui.disable_reminder->isChecked()) + s.setValue("quiet-update-version", str); + } + } + buf.clear(); + r->deleteLater(); + } + void on_ready() + { + buf.append(r->readAll()); + } + void maybe_show_dialog() + { + static auto uri = QStringLiteral("http://www.trackhat.org/#!opentrackversion/c1oxn"); + r = qnam.get(QNetworkRequest(uri)); + + QObject::connect(r, &QNetworkReply::finished, [&]() { on_finished(); }); + QObject::connect(r, &QNetworkReply::readyRead, [&]() { on_ready(); }); + } + }; +private: + Ui::UpdateDialog ui; + query& q; +private slots: + void close(QAbstractButton*) + { + QDialog::close(); + } +public: + update_dialog(QWidget* parent, query& q, const QString& new_version) : QDialog(parent), q(q) + { + ui.setupUi(this); + ui.ver_current->setText(const_cast<const char*>(opentrack_version)); + ui.ver_new->setTextFormat(Qt::RichText); + ui.ver_new->setText("<a href='http://www.trackhat.org/#!trackhat-opentrack/c1jzc'>" + new_version + "</a>"); + ui.ver_new->setOpenExternalLinks(true); + connect(ui.buttonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(close(QAbstractButton*))); + } +}; diff --git a/gui/software-update.ui b/gui/software-update.ui new file mode 100644 index 00000000..07edf66c --- /dev/null +++ b/gui/software-update.ui @@ -0,0 +1,118 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>UpdateDialog</class> + <widget class="QDialog" name="UpdateDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>385</width> + <height>187</height> + </rect> + </property> + <property name="windowTitle"> + <string>Dialog</string> + </property> + <layout class="QVBoxLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="font"> + <font> + <pointsize>16</pointsize> + </font> + </property> + <property name="text"> + <string>Software update released</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item> + <widget class="Line" name="line"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <widget class="QFrame" name="frame"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <layout class="QGridLayout" name="gridLayout"> + <property name="leftMargin"> + <number>12</number> + </property> + <property name="topMargin"> + <number>12</number> + </property> + <property name="rightMargin"> + <number>12</number> + </property> + <property name="bottomMargin"> + <number>12</number> + </property> + <property name="spacing"> + <number>12</number> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Current version:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLabel" name="ver_current"> + <property name="text"> + <string>TextLabel</string> + </property> + <property name="openExternalLinks"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Released version:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLabel" name="ver_new"> + <property name="text"> + <string>TextLabel</string> + </property> + </widget> + </item> + <item row="2" column="0" colspan="2"> + <widget class="QCheckBox" name="disable_reminder"> + <property name="text"> + <string>Don't remind me again about this version</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="standardButtons"> + <set>QDialogButtonBox::Close</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/gui/trackhat-wizard.ui b/gui/trackhat-wizard.ui new file mode 100644 index 00000000..09f68c03 --- /dev/null +++ b/gui/trackhat-wizard.ui @@ -0,0 +1,189 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>wizard</class> + <widget class="QWizard" name="wizard"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>365</width> + <height>586</height> + </rect> + </property> + <property name="modal"> + <bool>true</bool> + </property> + <property name="wizardStyle"> + <enum>QWizard::AeroStyle</enum> + </property> + <property name="options"> + <set>QWizard::NoCancelButton</set> + </property> + <widget class="QWizardPage" name="page_model"> + <property name="title"> + <string>Select a model</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QFrame" name="frame_7"> + <property name="styleSheet"> + <string notr="true">QFrame { + border: 0; + background: transparent; +}</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <property name="leftMargin"> + <number>20</number> + </property> + <property name="bottomMargin"> + <number>12</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <item row="0" column="1"> + <widget class="QLabel" name="label_12"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>120</width> + <height>108</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>120</width> + <height>108</height> + </size> + </property> + <property name="text"> + <string/> + </property> + <property name="pixmap"> + <pixmap resource="ui-res.qrc">:/images/trackhat-hat.png</pixmap> + </property> + <property name="scaledContents"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLabel" name="label_46"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>130</width> + <height>130</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>130</width> + <height>130</height> + </size> + </property> + <property name="text"> + <string/> + </property> + <property name="pixmap"> + <pixmap resource="ui-res.qrc">:/images/trackhat-clip-right.png</pixmap> + </property> + <property name="scaledContents"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLabel" name="label_48"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>130</width> + <height>130</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>130</width> + <height>130</height> + </size> + </property> + <property name="text"> + <string/> + </property> + <property name="pixmap"> + <pixmap resource="ui-res.qrc">:/images/trackhat-clip-left.png</pixmap> + </property> + <property name="scaledContents"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QRadioButton" name="cap_model"> + <property name="text"> + <string>Cap</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QRadioButton" name="clip_model"> + <property name="text"> + <string>Clip, right-handed</string> + </property> + <property name="checked"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QRadioButton" name="clip_model_left"> + <property name="text"> + <string>Clip, left-handed</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <widget class="QWizardPage" name="page_done"> + <property name="title"> + <string>We're all done!</string> + </property> + <layout class="QGridLayout" name="gridLayout_7"> + <item row="0" column="0"> + <widget class="QLabel" name="label_6"> + <property name="text"> + <string><html><head/><body><p>You can now use your new hardware and thanks for flying TrackHat.</p></body></html></string> + </property> + </widget> + </item> + </layout> + </widget> + </widget> + <resources> + <include location="ui-res.qrc"/> + </resources> + <connections/> +</ui> diff --git a/gui/trans_calib.cpp b/gui/trans_calib.cpp new file mode 100644 index 00000000..a1a4b641 --- /dev/null +++ b/gui/trans_calib.cpp @@ -0,0 +1,41 @@ +/* Copyright (c) 2012 Patrick Ruoff + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#include "trans_calib.h" + +TranslationCalibrator::TranslationCalibrator() +{ + reset(); +} + +void TranslationCalibrator::reset() +{ + P = cv::Matx66f::zeros(); + y = cv::Vec6f(0,0,0, 0,0,0); +} + +void TranslationCalibrator::update(const cv::Matx33f& R_CM_k, const cv::Vec3f& t_CM_k) +{ + cv::Matx<float, 6,3> H_k_T = cv::Matx<float, 6,3>::zeros(); + for (int i=0; i<3; ++i) { + for (int j=0; j<3; ++j) { + H_k_T(i,j) = R_CM_k(j,i); + } + } + for (int i=0; i<3; ++i) + { + H_k_T(3+i,i) = 1.0; + } + P += H_k_T * H_k_T.t(); + y += H_k_T * t_CM_k; +} + +cv::Vec3f TranslationCalibrator::get_estimate() +{ + cv::Vec6f x = P.inv() * y; + return cv::Vec3f(-x[0], -x[1], -x[2]); +} diff --git a/gui/trans_calib.h b/gui/trans_calib.h new file mode 100644 index 00000000..e20fc767 --- /dev/null +++ b/gui/trans_calib.h @@ -0,0 +1,39 @@ +/* Copyright (c) 2012 Patrick Ruoff + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#ifndef TRANSCALIB_H +#define TRANSCALIB_H + +#include <opencv2/core/core.hpp> + +//----------------------------------------------------------------------------- +// Calibrates the translation from head to model = t_MH +// by recursive least squares / +// kalman filter in information form with identity noise covariance +// measurement equation when head position = t_CH is fixed: +// (R_CM_k , Id)*(-t_MH, t_CH) = t_CM_k + +class TranslationCalibrator +{ +public: + TranslationCalibrator(); + + // reset the calibration process + void reset(); + + // update the current estimate + void update(const cv::Matx33f& R_CM_k, const cv::Vec3f& t_CM_k); + + // get the current estimate for t_MH + cv::Vec3f get_estimate(); + +private: + cv::Matx66f P; // normalized precision matrix = inverse covariance + cv::Vec6f y; // P*(-t_MH, t_CH) +}; + +#endif //TRANSCALIB_H diff --git a/gui/ui-res.qrc b/gui/ui-res.qrc new file mode 100644 index 00000000..ec1c7bba --- /dev/null +++ b/gui/ui-res.qrc @@ -0,0 +1,13 @@ +<RCC> + <qresource prefix="/"> + <file>images/tools.png</file> + <file>images/settings16.png</file> + <file>images/curves.png</file> + <file>images/facetracknoir.png</file> + <file>images/no-feed.png</file> + <file>images/filter-16.png</file> + <file>images/trackhat-clip-left.png</file> + <file>images/trackhat-clip-right.png</file> + <file>images/trackhat-hat.png</file> + </qresource> +</RCC> diff --git a/gui/ui.cpp b/gui/ui.cpp new file mode 100644 index 00000000..86c9fa9c --- /dev/null +++ b/gui/ui.cpp @@ -0,0 +1,546 @@ +/* Copyright (c) 2013-2015, Stanislaw Halik <sthalik@misaki.pl> + + * Permission to use, copy, modify, and/or distribute this + * software for any purpose with or without fee is hereby granted, + * provided that the above copyright notice and this permission + * notice appear in all copies. + */ + +#include "ui.h" +#include "opentrack/tracker.h" +#include "opentrack/options.hpp" +#include "tracker-pt/ftnoir_tracker_pt.h" +#include "filter-accela/ftnoir_filter_accela.h" +#include "new_file_dialog.h" +#include <QFileDialog> +#include <QDesktopServices> + +#ifndef _WIN32 +# include <unistd.h> +#else +# include <windows.h> +#endif + +MainWindow::MainWindow() : + pose_update_timer(this), + kbd_quit(QKeySequence("Ctrl+Q"), this), + no_feed_pixmap(":/images/no-feed.png"), + is_refreshing_profiles(false), + update_query(this) +{ + ui.setupUi(this); + + setFixedSize(size()); + + updateButtonState(false, false); + ui.video_frame_label->setPixmap(no_feed_pixmap); + + connect(ui.btnEditCurves, SIGNAL(clicked()), this, SLOT(showCurveConfiguration())); + connect(ui.btnShortcuts, SIGNAL(clicked()), this, SLOT(show_options_dialog())); + connect(ui.btnShowServerControls, SIGNAL(clicked()), this, SLOT(showProtocolSettings())); + + for (auto x : modules.protocols()) + ui.iconcomboProtocol->addItem(x->icon, x->name); + + refresh_config_list(); + connect(&config_list_timer, SIGNAL(timeout()), this, SLOT(refresh_config_list())); + config_list_timer.start(1000 * 3); + + tie_setting(s.protocol_dll, ui.iconcomboProtocol); + + connect(ui.iconcomboProtocol, + &QComboBox::currentTextChanged, + [&](QString) -> void { if (pProtocolDialog) pProtocolDialog = nullptr; save(); }); + + connect(ui.btnStartTracker, SIGNAL(clicked()), this, SLOT(startTracker())); + connect(ui.btnStopTracker, SIGNAL(clicked()), this, SLOT(stopTracker())); + connect(ui.iconcomboProfile, SIGNAL(currentTextChanged(QString)), this, SLOT(profileSelected(QString))); + + connect(&pose_update_timer, SIGNAL(timeout()), this, SLOT(showHeadPose())); + connect(&kbd_quit, SIGNAL(activated()), this, SLOT(exit())); + + save_timer.setSingleShot(true); + connect(&save_timer, SIGNAL(timeout()), this, SLOT(_save())); + + profile_menu.addAction("Create new empty config", this, SLOT(make_empty_config())); + profile_menu.addAction("Create new copied config", this, SLOT(make_copied_config())); + profile_menu.addAction("Open configuration directory", this, SLOT(open_config_directory())); + ui.profile_button->setMenu(&profile_menu); + + kbd_quit.setEnabled(true); + + connect(&det_timer, SIGNAL(timeout()), this, SLOT(maybe_start_profile_from_executable())); + det_timer.start(1000); + + ensure_tray(); + set_working_directory(); + + if (!QFile(group::ini_pathname()).exists()) + { + set_profile(OPENTRACK_DEFAULT_CONFIG); + const auto pathname = group::ini_pathname(); + if (!QFile(pathname).exists()) + { + QFile file(pathname); + (void) file.open(QFile::ReadWrite); + } + } + + if (group::ini_directory() == "") + QMessageBox::warning(this, + "Configuration not saved.", + "Can't create configuration directory! Expect major malfunction.", + QMessageBox::Ok, QMessageBox::NoButton); + + ui.btnStartTracker->setFocus(); + + update_query.maybe_show_dialog(); +} + +void MainWindow::closeEvent(QCloseEvent *e) +{ + if (maybe_not_close_tracking()) + e->ignore(); + else + e->accept(); +} + +bool MainWindow::get_new_config_name_from_dialog(QString& ret) +{ + new_file_dialog dlg; + dlg.exec(); + return dlg.is_ok(ret); +} + +MainWindow::~MainWindow() +{ + maybe_save(); + + if (tray) + tray->hide(); + stopTracker(); +} + +void MainWindow::set_working_directory() +{ + QDir::setCurrent(QCoreApplication::applicationDirPath()); +} + +void MainWindow::save_mappings() { + pose.save_mappings(); +} + +void MainWindow::save() +{ + save_timer.stop(); + save_timer.start(5000); +} + +void MainWindow::maybe_save() +{ + if (save_timer.isActive()) + { + save_timer.stop(); + _save(); + } +} + +void MainWindow::_save() { + s.b->save(); + save_mappings(); + mem<QSettings> settings = group::ini_file(); + settings->sync(); + +#if defined(__unix) || defined(__linux) + QString currentFile = group::ini_pathname(); + QByteArray bytes = QFile::encodeName(currentFile); + const char* filename_as_asciiz = bytes.constData(); + + if (access(filename_as_asciiz, R_OK | W_OK)) + { + QMessageBox::warning(this, "Something went wrong", "Check permissions and ownership for your .ini file!", QMessageBox::Ok, QMessageBox::NoButton); + } +#endif +} + +void MainWindow::load_mappings() { + pose.load_mappings(); +} + +void MainWindow::load_settings() { + s.b->reload(); + load_mappings(); +} + +void MainWindow::make_empty_config() +{ + QString name; + const QString dir = group::ini_directory(); + if (dir != "" && get_new_config_name_from_dialog(name)) + { + QFile filename(dir + "/" + name); + (void) filename.open(QFile::ReadWrite); + refresh_config_list(); + ui.iconcomboProfile->setCurrentText(name); + } +} + +void MainWindow::make_copied_config() +{ + const QString dir = group::ini_directory(); + const QString cur = group::ini_pathname(); + QString name; + if (cur != "" && dir != "" && get_new_config_name_from_dialog(name)) + { + const QString new_name = dir + "/" + name; + (void) QFile::remove(new_name); + (void) QFile::copy(cur, new_name); + refresh_config_list(); + ui.iconcomboProfile->setCurrentText(name); + } +} + +void MainWindow::open_config_directory() +{ + const QString path = group::ini_directory(); + if (path != "") + { + QDesktopServices::openUrl("file:///" + QDir::toNativeSeparators(path)); + } +} + +extern "C" const char* opentrack_version; + +void MainWindow::refresh_config_list() +{ + if (work) + return; + + if (group::ini_list().size() == 0) + { + QFile filename(group::ini_directory() + "/" OPENTRACK_DEFAULT_CONFIG); + (void) filename.open(QFile::ReadWrite); + } + + QStringList ini_list = group::ini_list(); + set_title(); + QString current = group::ini_filename(); + is_refreshing_profiles = true; + ui.iconcomboProfile->clear(); + for (auto x : ini_list) + ui.iconcomboProfile->addItem(QIcon(":/images/settings16.png"), x); + is_refreshing_profiles = false; + ui.iconcomboProfile->setCurrentText(current); +} + +void MainWindow::updateButtonState(bool running, bool inertialp) +{ + bool not_running = !running; + ui.iconcomboProfile->setEnabled ( not_running ); + ui.btnStartTracker->setEnabled ( not_running ); + ui.btnStopTracker->setEnabled ( running ); + ui.iconcomboProtocol->setEnabled ( not_running ); + ui.video_frame_label->setVisible(not_running || inertialp); + ui.profile_button->setEnabled(not_running); +} + +void MainWindow::reload_options() +{ + if (work) + work->reload_shortcuts(); + ensure_tray(); +} + +void MainWindow::startTracker() { + // tracker dtor needs run first + work = nullptr; + + libs = SelectedLibraries(ui.video_frame, std::make_shared<Tracker_PT>(), current_protocol(), std::make_shared<FTNoIR_Filter>()); + + { + double p[6] = {0,0,0, 0,0,0}; + display_pose(p, p); + } + + if (!libs.correct) + { + QMessageBox::warning(this, "Library load error", + "One of libraries failed to load. Check installation.", + QMessageBox::Ok, + QMessageBox::NoButton); + libs = SelectedLibraries(); + return; + } + + work = std::make_shared<Work>(s, pose, libs, this, winId()); + + reload_options(); + + if (pProtocolDialog) + pProtocolDialog->register_protocol(libs.pProtocol.get()); + + pose_update_timer.start(50); + + // NB check valid since SelectedLibraries ctor called + // trackers take care of layout state updates + const bool is_inertial = ui.video_frame->layout() == nullptr; + updateButtonState(true, is_inertial); + + maybe_save(); + + ui.btnStopTracker->setFocus(); +} + +void MainWindow::stopTracker( ) { + //ui.game_name->setText("Not connected"); + + pose_update_timer.stop(); + ui.pose_display->rotateBy(0, 0, 0, 0, 0, 0); + + if (pProtocolDialog) + pProtocolDialog->unregister_protocol(); + + work = nullptr; + libs = SelectedLibraries(); + + { + double p[6] = {0,0,0, 0,0,0}; + display_pose(p, p); + } + updateButtonState(false, false); + + set_title(); + + ui.btnStartTracker->setFocus(); +} + +void MainWindow::display_pose(const double *mapped, const double *raw) +{ + ui.pose_display->rotateBy(mapped[Yaw], mapped[Pitch], mapped[Roll], + mapped[TX], mapped[TY], mapped[TZ]); + + if (mapping_widget) + mapping_widget->update(); + + double mapped_[6], raw_[6]; + + for (int i = 0; i < 6; i++) + { + mapped_[i] = (int) mapped[i]; + raw_[i] = (int) raw[i]; + } + + ui.raw_x->display(raw_[TX]); + ui.raw_y->display(raw_[TY]); + ui.raw_z->display(raw_[TZ]); + ui.raw_yaw->display(raw_[Yaw]); + ui.raw_pitch->display(raw_[Pitch]); + ui.raw_roll->display(raw_[Roll]); + + ui.pose_x->display(mapped_[TX]); + ui.pose_y->display(mapped_[TY]); + ui.pose_z->display(mapped_[TZ]); + ui.pose_yaw->display(mapped_[Yaw]); + ui.pose_pitch->display(mapped_[Pitch]); + ui.pose_roll->display(mapped_[Roll]); + + QString game_title; + if (libs.pProtocol) + game_title = libs.pProtocol->game_name(); + set_title(game_title); +} + +void MainWindow::set_title(const QString& game_title_) +{ + QString game_title; + if (game_title_ != "") + game_title = " :: " + game_title_; + QString current = group::ini_filename(); + setWindowTitle(opentrack_version + QStringLiteral(" opentrack") + QStringLiteral(" :: ") + current + game_title); +} + +void MainWindow::showHeadPose() +{ + double mapped[6], raw[6]; + + work->tracker->get_raw_and_mapped_poses(mapped, raw); + + display_pose(mapped, raw); +} + +template<typename t> +bool mk_dialog(mem<dylib> lib, mem<t>* orig) +{ + if (*orig && (*orig)->isVisible()) + { + (*orig)->show(); + (*orig)->raise(); + return false; + } + + if (lib && lib->Dialog) + { + auto dialog = mem<t>(reinterpret_cast<t*>(lib->Dialog())); + dialog->setWindowFlags(Qt::Dialog); + dialog->setFixedSize(dialog->size()); + + *orig = dialog; + dialog->show(); + dialog->raise(); + + return true; + } + + return false; +} +void MainWindow::showProtocolSettings() { + if (mk_dialog(current_protocol(), &pProtocolDialog) && libs.pProtocol) + pProtocolDialog->register_protocol(libs.pProtocol.get()); +} +template<typename t, typename... Args> +bool mk_window(mem<t>* place, Args... params) +{ + if (*place && (*place)->isVisible()) + { + (*place)->show(); + (*place)->raise(); + return false; + } + else + { + *place = std::make_shared<t>(params...); + (*place)->setWindowFlags(Qt::Dialog); + (*place)->show(); + (*place)->raise(); + return true; + } +} + +void MainWindow::show_options_dialog() { + if (mk_window<OptionsDialog, State&>(&options_widget, static_cast<State&>(*this))) + connect(options_widget.get(), SIGNAL(reload()), this, SLOT(reload_options())); +} + +void MainWindow::showCurveConfiguration() { + mk_window<MapWidget, Mappings&, main_settings&>(&mapping_widget, pose, s); +} + +bool MainWindow::maybe_not_close_tracking() +{ + if (work != nullptr) + { + auto btn = QMessageBox::warning(this, "Tracking active", + "Are you sure you want to exit? This will terminate tracking.", + QMessageBox::Yes, QMessageBox::No); + if (btn == QMessageBox::No) + return true; + } + return false; +} + +void MainWindow::exit() { + + if (!maybe_not_close_tracking()) + QCoreApplication::exit(0); +} + +void MainWindow::profileSelected(QString name) +{ + maybe_save(); + + if (name == "" || is_refreshing_profiles) + return; + + const auto old_name = group::ini_filename(); + const auto new_name = name; + + if (old_name != new_name) + { + save(); + + { + QSettings settings(OPENTRACK_ORG); + settings.setValue (OPENTRACK_CONFIG_FILENAME_KEY, new_name); + } + + set_title(); + load_settings(); + } +} + +void MainWindow::shortcutRecentered() +{ + qDebug() << "Center"; + if (work) + work->tracker->center(); +} + +void MainWindow::shortcutToggled() +{ + qDebug() << "Toggle"; + if (work) + work->tracker->toggle_enabled(); +} + +void MainWindow::shortcutZeroed() +{ + qDebug() << "Zero"; + if (work) + work->tracker->zero(); +} + +void MainWindow::ensure_tray() +{ + if (tray) + tray->hide(); + tray = nullptr; + if (s.tray_enabled) + { + tray = std::make_shared<QSystemTrayIcon>(this); + tray->setIcon(QIcon(":/images/facetracknoir.png")); + tray->show(); + connect(tray.get(), SIGNAL(activated(QSystemTrayIcon::ActivationReason)), + this, SLOT(restore_from_tray(QSystemTrayIcon::ActivationReason))); + } +} + +void MainWindow::restore_from_tray(QSystemTrayIcon::ActivationReason) +{ + show(); + setWindowState(Qt::WindowNoState); +} + +void MainWindow::changeEvent(QEvent* e) +{ + if (s.tray_enabled && e->type() == QEvent::WindowStateChange && (windowState() & Qt::WindowMinimized)) + { + if (!tray) + ensure_tray(); + hide(); + } + QMainWindow::changeEvent(e); +} + +void MainWindow::maybe_start_profile_from_executable() +{ + if (!work) + { + QString prof; + if (det.config_to_start(prof)) + { + ui.iconcomboProfile->setCurrentText(prof); + startTracker(); + } + } + else + { + if (det.should_stop()) + stopTracker(); + } +} + +void MainWindow::set_profile(const QString &profile) +{ + QSettings settings(OPENTRACK_ORG); + settings.setValue(OPENTRACK_CONFIG_FILENAME_KEY, profile); +} diff --git a/gui/ui.h b/gui/ui.h new file mode 100644 index 00000000..c1e71ca9 --- /dev/null +++ b/gui/ui.h @@ -0,0 +1,105 @@ +/* Copyright (c) 2014-2015, Stanislaw Halik <sthalik@misaki.pl> + + * Permission to use, copy, modify, and/or distribute this + * software for any purpose with or without fee is hereby granted, + * provided that the above copyright notice and this permission + * notice appear in all copies. + */ + +#pragma once + +#include <QMainWindow> +#include <QKeySequence> +#include <QShortcut> +#include <QPixmap> +#include <QTimer> +#include <QSystemTrayIcon> +#include <QString> +#include <QMenu> + +#include "ui_main.h" + +#include "opentrack/options.hpp" +#include "opentrack/main-settings.hpp" +#include "opentrack/plugin-support.hpp" +#include "opentrack/tracker.h" +#include "opentrack/shortcuts.h" +#include "opentrack/work.hpp" +#include "opentrack/state.hpp" +#include "curve-config.h" +#include "options-dialog.hpp" +#include "process_detector.h" +#include "software-update-dialog.hpp" + +using namespace options; + +class MainWindow : public QMainWindow, private State +{ + Q_OBJECT + + Ui::OpentrackUI ui; + mem<QSystemTrayIcon> tray; + QTimer pose_update_timer; + QTimer det_timer; + QTimer config_list_timer; + mem<OptionsDialog> options_widget; + mem<MapWidget> mapping_widget; + QShortcut kbd_quit; + QPixmap no_feed_pixmap; + mem<IProtocolDialog> pProtocolDialog; + process_detector_worker det; + QMenu profile_menu; + bool is_refreshing_profiles; + QTimer save_timer; + update_dialog::query update_query; + + mem<dylib> current_protocol() + { + return modules.protocols().value(ui.iconcomboProtocol->currentIndex(), nullptr); + } + + void changeEvent(QEvent* e) override; + + void load_settings(); + void updateButtonState(bool running, bool inertialp); + void display_pose(const double* mapped, const double* raw); + void ensure_tray(); + void set_title(const QString& game_title = QStringLiteral("")); + static bool get_new_config_name_from_dialog(QString &ret); + void set_profile(const QString& profile); + void maybe_save(); + bool maybe_not_close_tracking(); + void closeEvent(QCloseEvent *e) override; +private slots: + void _save(); + void save(); + void exit(); + void profileSelected(QString name); + + void showProtocolSettings(); + void show_options_dialog(); + void showCurveConfiguration(); + void showHeadPose(); + + void restore_from_tray(QSystemTrayIcon::ActivationReason); + void maybe_start_profile_from_executable(); + + void make_empty_config(); + void make_copied_config(); + void open_config_directory(); + void refresh_config_list(); + + void startTracker(); + void stopTracker(); + void reload_options(); +public slots: + void shortcutRecentered(); + void shortcutToggled(); + void shortcutZeroed(); +public: + MainWindow(); + ~MainWindow(); + void save_mappings(); + void load_mappings(); + static void set_working_directory(); +}; diff --git a/gui/wizard.cpp b/gui/wizard.cpp new file mode 100644 index 00000000..4b0ccba0 --- /dev/null +++ b/gui/wizard.cpp @@ -0,0 +1,80 @@ +#include "wizard.h" +#include "opentrack/state.hpp" +#include "tracker-pt/ftnoir_tracker_pt_settings.h" +#include "filter-accela/ftnoir_filter_accela.h" + +Wizard::Wizard() : QWizard(nullptr) +{ + ui.setupUi(this); + connect(this, SIGNAL(accepted()), this, SLOT(set_data())); +} + +static constexpr double tz[][2] = { + { 16.5327205657959, 13.0232553482056 }, + { 55.4535026550293, 100 }, + { 56.8312301635742, 100 }, + { -1, -1 }, +}; + +static constexpr double yaw[][2] = { + { 10.7462686567164, 20.9302325581395 }, + { 41.9517784118652, 180 }, + { -1, -1 }, +}; + +static constexpr double pitch[][2] = { + { 10.1262916188289, 27.6279069767442 }, + { 32.4454649827784, 180 }, + { -1, -1 }, +}; + +static constexpr double roll[][2] = { + { 12.3995409011841, 25.9534893035889 }, + { 54.3513221740723, 180 }, + { -1, -1 }, +}; + +static void set_mapping(Mapping& m, const double spline[][2]) +{ + m.opts.altp = false; + m.curve.removeAllPoints(); + for (int i = 0; spline[i][0] >= 0; i++) + m.curve.addPoint(QPointF(spline[i][0], spline[i][1])); +} + +void Wizard::set_data() +{ + Model m; + + if (ui.clip_model->isChecked()) + m = ClipRight; + else if (ui.clip_model_left->isChecked()) + m = ClipLeft; + else // ui.cap_model + m = Cap; + + State state; + + set_mapping(state.pose(TZ), tz); + set_mapping(state.pose(Yaw), yaw); + set_mapping(state.pose(Pitch), pitch); + set_mapping(state.pose(Roll), roll); + state.pose.save_mappings(); + + settings_pt pt; + pt.threshold = 31; + pt.min_point_size = 0; + pt.max_point_size = 50; + pt.fov = 1; + pt.camera_mode = 0; + pt.model_used = m; + pt.b->save(); + + settings_accela acc; + acc.ewma = 49; + acc.rot_threshold = 29; + acc.rot_deadzone = 29; + acc.trans_deadzone = 33; + acc.trans_threshold = 19; + acc.b->save(); +} diff --git a/gui/wizard.h b/gui/wizard.h new file mode 100644 index 00000000..ea848e36 --- /dev/null +++ b/gui/wizard.h @@ -0,0 +1,21 @@ +#pragma once + +#include "opentrack/options.hpp" +#include "opentrack/main-settings.hpp" +#include "opentrack/mappings.hpp" +#include "ui_trackhat-wizard.h" +#include <QObject> +#include <QWizard> + +class Wizard : public QWizard +{ + Q_OBJECT + Ui_wizard ui; +public: + Wizard(); + + enum Model { Cap = 0, ClipRight = 1, ClipLeft = 2 }; + enum { ClipRightX = 135, ClipLeftX = -135 }; +private slots: + void set_data(); +}; |