summaryrefslogtreecommitdiffhomepage
path: root/variant/default
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2018-01-16 04:33:14 +0100
committerStanislaw Halik <sthalik@misaki.pl>2018-01-16 06:45:52 +0100
commit2b1c5593b0bc1ebfcd2e808f128e4b0312f59d93 (patch)
treee7e8f5d8d3af88a6df37cbd482edcbd3ff8def26 /variant/default
parent3583e3d3cd0b6ca2515ada16ca7dcc8cce83031f (diff)
gui, variant/default: move default UI
Diffstat (limited to 'variant/default')
-rw-r--r--variant/default/main-window.cpp945
-rw-r--r--variant/default/main-window.hpp158
-rw-r--r--variant/default/main-window.ui1453
-rw-r--r--variant/default/main.cpp2
-rw-r--r--variant/default/new_config.ui45
-rw-r--r--variant/default/new_file_dialog.cpp39
-rw-r--r--variant/default/new_file_dialog.h25
7 files changed, 2666 insertions, 1 deletions
diff --git a/variant/default/main-window.cpp b/variant/default/main-window.cpp
new file mode 100644
index 00000000..9d27afdc
--- /dev/null
+++ b/variant/default/main-window.cpp
@@ -0,0 +1,945 @@
+/* Copyright (c) 2013-2016, 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 "main-window.hpp"
+#include "logic/pipeline.hpp"
+#include "options/options.hpp"
+#include "opentrack-library-path.h"
+#include "new_file_dialog.h"
+#include "migration/migration.hpp"
+#include "compat/check-visible.hpp"
+#include "compat/sleep.hpp"
+#include "compat/macros.hpp"
+
+#include <QMessageBox>
+#include <QDesktopServices>
+#include <QDir>
+
+extern "C" const char* const opentrack_version;
+
+#if !defined EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+#endif
+
+#if !defined EXIT_FAILURE
+# define EXIT_FAILURE 1
+#endif
+
+/* FreeBSD sysexits(3)
+ *
+ * The input data was incorrect in some way. This
+ * should only be used for user's data and not system
+ * files.
+ */
+
+#if !defined _WIN32 && !defined __APPLE__
+# include <unistd.h>
+void MainWindow::annoy_if_root()
+{
+ if (geteuid() == 0)
+ {
+ portable::sleep(4000);
+ QMessageBox::critical(this,
+ tr("Running as root is bad"),
+ tr("Do not run as root. Set correct device node permissions."),
+ QMessageBox::Ok);
+ portable::sleep(4000);
+ QMessageBox::critical(this,
+ tr("Running as root is bad, seriously"),
+ tr("Do not run as root. I'll keep whining at every startup."),
+ QMessageBox::Ok);
+ portable::sleep(4000);
+ QMessageBox::critical(this,
+ tr("Running as root is really seriously bad"),
+ tr("Do not run as root. Be annoyed, comprehensively."),
+ QMessageBox::Ok);
+ }
+}
+#endif
+
+main_window::main_window() :
+ State(OPENTRACK_BASE_PATH + OPENTRACK_LIBRARY_PATH)
+{
+ ui.setupUi(this);
+
+#if !defined _WIN32 && !defined __APPLE__
+ annoy_if_root();
+#endif
+
+ setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | windowFlags());
+
+ update_button_state(false, false);
+
+ if (group::ini_directory().size() == 0)
+ {
+ die_on_config_not_writable();
+ return;
+ }
+
+ if (!refresh_config_list())
+ {
+ exit(64);
+ return;
+ }
+
+ connect(ui.btnEditCurves, SIGNAL(clicked()), this, SLOT(show_mapping_window()));
+ connect(ui.btnShortcuts, SIGNAL(clicked()), this, SLOT(show_options_dialog()));
+ connect(ui.btnShowEngineControls, SIGNAL(clicked()), this, SLOT(show_tracker_settings()));
+ connect(ui.btnShowServerControls, SIGNAL(clicked()), this, SLOT(show_proto_settings()));
+ connect(ui.btnShowFilterControls, SIGNAL(clicked()), this, SLOT(show_filter_settings()));
+ connect(ui.btnStartTracker, SIGNAL(clicked()), this, SLOT(start_tracker_()));
+ connect(ui.btnStopTracker, SIGNAL(clicked()), this, SLOT(stop_tracker_()));
+ connect(ui.iconcomboProfile, &QComboBox::currentTextChanged, this, [&](const QString& x) { set_profile(x); });
+
+ // fill dylib comboboxen
+ {
+ modules.filters().push_front(std::make_shared<dylib>("", dylib::Filter));
+
+ for (std::shared_ptr<dylib>& x : modules.trackers())
+ ui.iconcomboTrackerSource->addItem(x->icon, x->name);
+
+ for (std::shared_ptr<dylib>& x : modules.protocols())
+ ui.iconcomboProtocol->addItem(x->icon, x->name);
+
+ for (std::shared_ptr<dylib>& x : modules.filters())
+ ui.iconcomboFilter->addItem(x->icon, x->name);
+ }
+
+ // timers
+ connect(&config_list_timer, &QTimer::timeout, this, [this]() { refresh_config_list(); });
+ connect(&pose_update_timer, SIGNAL(timeout()), this, SLOT(show_pose()), Qt::DirectConnection);
+ connect(&det_timer, SIGNAL(timeout()), this, SLOT(maybe_start_profile_from_executable()));
+
+ // ctrl+q exits
+ connect(&kbd_quit, SIGNAL(activated()), this, SLOT(exit()));
+
+ // profile menu
+ {
+ profile_menu.addAction(tr("Create new empty config"), this, SLOT(make_empty_config()));
+ profile_menu.addAction(tr("Create new copied config"), this, SLOT(make_copied_config()));
+ profile_menu.addAction(tr("Open configuration directory"), this, SLOT(open_config_directory()));
+ ui.profile_button->setMenu(&profile_menu);
+ }
+
+ {
+ const QString cur = group::ini_filename();
+ bool ok = is_config_listed(cur) ? set_profile(cur) : set_profile(OPENTRACK_DEFAULT_CONFIG);
+ if (!ok)
+ {
+ exit(64);
+ return;
+ }
+ }
+
+ // only tie and connect main screen options after migrations are done
+ // below is fine, set_profile() is called already
+
+ // dylibs
+ {
+ connect(ui.iconcomboTrackerSource,
+ &QComboBox::currentTextChanged,
+ this,
+ [&](const QString&) { if (pTrackerDialog) pTrackerDialog = nullptr; });
+
+ connect(ui.iconcomboTrackerSource,
+ &QComboBox::currentTextChanged,
+ this,
+ [&](const QString&) { if (pProtocolDialog) pProtocolDialog = nullptr; });
+
+ connect(ui.iconcomboTrackerSource,
+ &QComboBox::currentTextChanged,
+ this,
+ [&](const QString&) { if (pFilterDialog) pFilterDialog = nullptr; });
+
+ connect(&m.tracker_dll, base_value::value_changed<QString>(), this, &main_window::save_modules, Qt::DirectConnection);
+ connect(&m.protocol_dll, base_value::value_changed<QString>(), this, &main_window::save_modules, Qt::DirectConnection);
+ connect(&m.filter_dll, base_value::value_changed<QString>(), this, &main_window::save_modules, Qt::DirectConnection);
+
+ tie_setting(m.tracker_dll, ui.iconcomboTrackerSource);
+ tie_setting(m.protocol_dll, ui.iconcomboProtocol);
+ tie_setting(m.filter_dll, ui.iconcomboFilter);
+ }
+
+ connect(this, &main_window::start_tracker,
+ this, [&]() { qDebug() << "start tracker"; start_tracker_(); },
+ Qt::QueuedConnection);
+
+ connect(this, &main_window::stop_tracker,
+ this, [&]() { qDebug() << "stop tracker"; stop_tracker_(); },
+ Qt::QueuedConnection);
+
+ connect(this, &main_window::toggle_tracker,
+ this, [&]() { qDebug() << "toggle tracker"; if (work) stop_tracker_(); else start_tracker_(); },
+ Qt::QueuedConnection);
+
+ connect(this, &main_window::restart_tracker,
+ this, [&]() { qDebug() << "restart tracker"; stop_tracker_(); start_tracker_(); },
+ Qt::QueuedConnection);
+
+ init_tray();
+
+ register_shortcuts();
+ det_timer.start(1000);
+ config_list_timer.start(1000 * 5);
+ kbd_quit.setEnabled(true);
+
+ adjustSize();
+ setFixedSize(size());
+
+ if (!start_in_tray())
+ {
+ setVisible(true);
+ show();
+ }
+ else
+ setVisible(false);
+}
+
+void main_window::init_tray()
+{
+ tray_menu.clear();
+
+ QString display_name(opentrack_version);
+ if (display_name.startsWith("opentrack-"))
+ {
+ display_name = tr("opentrack") + " " + display_name.mid(sizeof("opentrack-") - 1);
+ }
+ if (display_name.endsWith("-DEBUG"))
+ display_name.replace(display_name.size() - int(sizeof("DEBUG")), display_name.size(), tr(" (debug)"));
+
+ menu_action_header.setEnabled(false);
+ menu_action_header.setText(display_name);
+ menu_action_header.setIcon(QIcon(":/images/facetracknoir.png"));
+ tray_menu.addAction(&menu_action_header);
+
+ menu_action_show.setIconVisibleInMenu(true);
+ menu_action_show.setText(isHidden() ? tr("Show the Octopus") : tr("Hide the Octopus"));
+ menu_action_show.setIcon(QIcon(":/images/facetracknoir.png"));
+ QObject::connect(&menu_action_show, &QAction::triggered, this, [&]() { toggle_restore_from_tray(QSystemTrayIcon::Trigger); });
+ tray_menu.addAction(&menu_action_show);
+
+ tray_menu.addSeparator();
+
+ menu_action_tracker.setText(tr("Tracker settings"));
+ menu_action_tracker.setIcon(QIcon(":/images/tools.png"));
+ QObject::connect(&menu_action_tracker, &QAction::triggered, this, &main_window::show_tracker_settings);
+ tray_menu.addAction(&menu_action_tracker);
+
+ menu_action_filter.setText(tr("Filter settings"));
+ menu_action_filter.setIcon(QIcon(":/images/filter-16.png"));
+ QObject::connect(&menu_action_filter, &QAction::triggered, this, &main_window::show_filter_settings);
+ tray_menu.addAction(&menu_action_filter);
+
+ menu_action_proto.setText(tr("Protocol settings"));
+ menu_action_proto.setIcon(QIcon(":/images/settings16.png"));
+ QObject::connect(&menu_action_proto, &QAction::triggered, this, &main_window::show_proto_settings);
+ tray_menu.addAction(&menu_action_proto);
+
+ tray_menu.addSeparator();
+
+ menu_action_mappings.setIcon(QIcon(":/images/curves.png"));
+ menu_action_mappings.setText(tr("Mappings"));
+ QObject::connect(&menu_action_mappings, &QAction::triggered, this, &main_window::show_mapping_window);
+ tray_menu.addAction(&menu_action_mappings);
+
+ menu_action_options.setIcon(QIcon(":/images/tools.png"));
+ menu_action_options.setText(tr("Options"));
+ QObject::connect(&menu_action_options, &QAction::triggered, this, &main_window::show_options_dialog);
+ tray_menu.addAction(&menu_action_options);
+
+ tray_menu.addSeparator();
+
+ menu_action_exit.setText(tr("Exit"));
+ QObject::connect(&menu_action_exit, &QAction::triggered, this, &main_window::exit);
+ tray_menu.addAction(&menu_action_exit);
+
+ connect(&s.tray_enabled,
+ static_cast<void (base_value::*)(bool) const>(&base_value::valueChanged),
+ this,
+ &main_window::ensure_tray);
+}
+
+void main_window::register_shortcuts()
+{
+ using t_key = Shortcuts::t_key;
+ using t_keys = Shortcuts::t_keys;
+
+ t_keys keys
+ {
+ t_key(s.key_start_tracking1, [&](bool) { start_tracker(); }, true),
+ t_key(s.key_start_tracking2, [&](bool) { start_tracker(); }, true),
+
+ t_key(s.key_stop_tracking1, [&](bool) { stop_tracker(); }, true),
+ t_key(s.key_stop_tracking2, [&](bool) { stop_tracker(); }, true),
+
+ t_key(s.key_toggle_tracking1, [&](bool) { toggle_tracker(); }, true),
+ t_key(s.key_toggle_tracking2, [&](bool) { toggle_tracker(); }, true),
+
+ t_key(s.key_restart_tracking1, [&](bool) { restart_tracker(); }, true),
+ t_key(s.key_restart_tracking2, [&](bool) { restart_tracker(); }, true),
+ };
+
+ global_shortcuts.reload(keys);
+
+ if (work)
+ work->reload_shortcuts();
+}
+
+void main_window::die_on_config_not_writable()
+{
+ stop_tracker_();
+
+ static const QString pad(16, QChar(' '));
+
+ QMessageBox::critical(this,
+ tr("The Octopus is sad"),
+ tr("Check permissions for your .ini directory:\n\n\"%1\"%2\n\nExiting now.").arg(group::ini_directory()).arg(pad),
+ QMessageBox::Close, QMessageBox::NoButton);
+
+ exit(64);
+}
+
+bool main_window::maybe_die_on_config_not_writable(const QString& current, QStringList* ini_list_)
+{
+ const bool writable =
+ group::with_settings_object([&](QSettings& s) {
+ return s.isWritable();
+ });
+
+ if (writable)
+ return false;
+
+ const bool open = QFile(group::ini_combine(current)).open(QFile::ReadWrite);
+ const QStringList ini_list = group::ini_list();
+
+ if (!ini_list.contains(current) || !open)
+ {
+ die_on_config_not_writable();
+ return true;
+ }
+
+ if (ini_list_ != nullptr)
+ *ini_list_ = ini_list;
+
+ return false;
+}
+
+bool main_window::get_new_config_name_from_dialog(QString& ret)
+{
+ new_file_dialog dlg;
+ dlg.exec();
+ return dlg.is_ok(ret);
+}
+
+main_window::~main_window()
+{
+ if (tray)
+ tray->hide();
+ tray = nullptr;
+
+ const bool just_stopping = bool(work);
+
+ // stupid ps3 eye has LED issues
+ if (just_stopping)
+ {
+ stop_tracker_();
+ close();
+ QEventLoop ev;
+ ev.processEvents();
+ portable::sleep(2000);
+ }
+}
+
+void main_window::set_working_directory()
+{
+ QDir::setCurrent(OPENTRACK_BASE_PATH);
+}
+
+void main_window::save_modules()
+{
+ qDebug() << "save modules";
+ m.b->save();
+}
+
+void main_window::make_empty_config()
+{
+ QString name;
+ if (get_new_config_name_from_dialog(name))
+ {
+ QFile(group::ini_combine(name)).open(QFile::ReadWrite);
+
+ if (!refresh_config_list())
+ return;
+
+ if (is_config_listed(name))
+ {
+ QSignalBlocker q(ui.iconcomboProfile);
+
+ if (!set_profile(name))
+ return;
+ mark_config_as_not_needing_migration();
+ }
+ }
+}
+
+void main_window::make_copied_config()
+{
+ const QString cur = group::ini_pathname();
+ QString name;
+ if (cur != "" && get_new_config_name_from_dialog(name))
+ {
+ const QString new_name = group::ini_combine(name);
+ (void) QFile::remove(new_name);
+ QFile::copy(cur, new_name);
+
+ if (!refresh_config_list())
+ return;
+
+ if (is_config_listed(name))
+ {
+ QSignalBlocker q(ui.iconcomboProfile);
+
+ if (!set_profile(name))
+ return;
+ mark_config_as_not_needing_migration();
+ }
+ }
+
+}
+
+void main_window::open_config_directory()
+{
+ QDesktopServices::openUrl("file:///" + QDir::toNativeSeparators(group::ini_directory()));
+}
+
+bool main_window::refresh_config_list()
+{
+ if (work)
+ return true;
+
+ QStringList ini_list = group::ini_list();
+
+ // check for sameness
+ const bool exact_same = ini_list.size() > 0 && progn(
+ if (ini_list.size() == ui.iconcomboProfile->count())
+ {
+ const int sz = ini_list.size();
+ for (int i = 0; i < sz; i++)
+ {
+ if (ini_list[i] != ui.iconcomboProfile->itemText(i))
+ return false;
+ }
+ return true;
+ }
+
+ return false;
+ );
+
+ QString current = group::ini_filename();
+
+ if (!ini_list.contains(current))
+ current = OPENTRACK_DEFAULT_CONFIG_Q;
+
+ if (maybe_die_on_config_not_writable(current, &ini_list))
+ return false;
+
+ if (exact_same)
+ return true;
+
+ const QIcon icon(":/images/settings16.png");
+
+ QSignalBlocker l(ui.iconcomboProfile);
+
+ ui.iconcomboProfile->clear();
+ ui.iconcomboProfile->addItems(ini_list);
+
+ for (int i = 0; i < ini_list.size(); i++)
+ ui.iconcomboProfile->setItemIcon(i, icon);
+
+ ui.iconcomboProfile->setCurrentText(current);
+
+ return true;
+}
+
+void main_window::update_button_state(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.iconcomboFilter->setEnabled(not_running);
+ ui.iconcomboTrackerSource->setEnabled(not_running);
+ ui.profile_button->setEnabled(not_running);
+ ui.video_frame_label->setVisible(not_running || inertialp);
+ if(not_running)
+ {
+ ui.video_frame_label->setPixmap(QPixmap(":/images/tracking-not-started.png"));
+ }
+ else {
+ ui.video_frame_label->setPixmap(QPixmap(":/images/no-feed.png"));
+ }
+}
+
+void main_window::start_tracker_()
+{
+ if (work)
+ return;
+
+ {
+ double p[6] = {0,0,0, 0,0,0};
+ display_pose(p, p);
+ }
+
+ work = std::make_shared<Work>(pose, ev, ui.video_frame, current_tracker(), current_protocol(), current_filter());
+
+ if (!work->is_ok())
+ {
+ work = nullptr;
+ return;
+ }
+
+ if (pTrackerDialog)
+ pTrackerDialog->register_tracker(work->libs.pTracker.get());
+
+ if (pFilterDialog)
+ pFilterDialog->register_filter(work->libs.pFilter.get());
+
+ if (pProtocolDialog)
+ pProtocolDialog->register_protocol(work->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;
+ update_button_state(true, is_inertial);
+
+ ui.btnStopTracker->setFocus();
+}
+
+void main_window::stop_tracker_()
+{
+ if (!work)
+ return;
+
+ with_tracker_teardown sentinel;
+
+ pose_update_timer.stop();
+ ui.pose_display->rotate_sync(0,0,0, 0,0,0);
+
+ if (pTrackerDialog)
+ pTrackerDialog->unregister_tracker();
+
+ if (pProtocolDialog)
+ pProtocolDialog->unregister_protocol();
+
+ if (pFilterDialog)
+ pFilterDialog->unregister_filter();
+
+ work = nullptr;
+
+ {
+ double p[6] = {0,0,0, 0,0,0};
+ display_pose(p, p);
+ }
+
+ update_button_state(false, false);
+ set_title();
+ ui.btnStartTracker->setFocus();
+}
+
+void main_window::display_pose(const double *mapped, const double *raw)
+{
+ ui.pose_display->rotate_async(mapped[Yaw], mapped[Pitch], -mapped[Roll],
+ mapped[TX], mapped[TY], mapped[TZ]);
+
+ QLCDNumber* raw_[] = {
+ ui.raw_x, ui.raw_y, ui.raw_z,
+ ui.raw_yaw, ui.raw_pitch, ui.raw_roll,
+ };
+
+ QLCDNumber* mapped_[] = {
+ ui.pose_x, ui.pose_y, ui.pose_z,
+ ui.pose_yaw, ui.pose_pitch, ui.pose_roll,
+ };
+
+ for (int k = 0; k < 6; k++)
+ {
+ raw_[k]->display(iround(raw[k]));
+ mapped_[k]->display(iround(mapped[k]));
+ }
+
+ QString game_title;
+ if (work && work->libs.pProtocol)
+ game_title = work->libs.pProtocol->game_name();
+ set_title(game_title);
+}
+
+void main_window::set_title(const QString& game_title_)
+{
+ QString game_title;
+ if (game_title_ != "")
+ game_title = tr(" :: ") + game_title_;
+ QString current = group::ini_filename();
+ QString version(opentrack_version);
+ version = tr("opentrack") + " " + version.mid(sizeof("opentrack-") - 1);
+ setWindowTitle(version + tr(" :: ") + current + game_title);
+}
+
+void main_window::show_pose()
+{
+ set_is_visible(*this);
+
+ if (mapping_widget)
+ mapping_widget->refresh_tab();
+
+ if (!check_is_visible())
+ return;
+
+ double mapped[6], raw[6];
+
+ work->tracker->raw_and_mapped_pose(mapped, raw);
+
+ display_pose(mapped, raw);
+}
+
+template<typename t, typename F>
+bool main_window::mk_window_common(std::unique_ptr<t>& d, F&& ctor)
+{
+ if (d)
+ {
+ d->show();
+ d->raise();
+
+ return false;
+ }
+ else if ((d = std::unique_ptr<t>(ctor())))
+ {
+ QWidget& w = *d;
+
+ w.setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | w.windowFlags());
+
+ w.setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+
+ w.show();
+ w.adjustSize();
+ w.setFixedSize(w.size());
+
+ return true;
+ }
+
+ return false;
+}
+
+template<typename t, typename... Args>
+inline bool main_window::mk_window(std::unique_ptr<t>& place, Args&&... params)
+{
+ return mk_window_common(place, [&]() { return new t(std::forward<Args>(params)...); });
+}
+
+template<typename t>
+bool main_window::mk_dialog(std::shared_ptr<dylib> lib, std::unique_ptr<t>& d)
+{
+ const bool just_created = mk_window_common(d, [&]() -> t* {
+ if (lib && lib->Dialog)
+ return (t*) lib->Dialog();
+ return nullptr;
+ });
+
+ return just_created;
+}
+
+void main_window::show_tracker_settings()
+{
+ if (mk_dialog(current_tracker(), pTrackerDialog) && work && work->libs.pTracker)
+ pTrackerDialog->register_tracker(work->libs.pTracker.get());
+ if (pTrackerDialog)
+ // must run bundle::reload(), don't remove next line
+ QObject::connect(pTrackerDialog.get(), &ITrackerDialog::closing,
+ this, [this]() { pTrackerDialog = nullptr; });
+}
+
+void main_window::show_proto_settings()
+{
+ if (mk_dialog(current_protocol(), pProtocolDialog) && work && work->libs.pProtocol)
+ pProtocolDialog->register_protocol(work->libs.pProtocol.get());
+ if (pProtocolDialog)
+ // must run bundle::reload(), don't remove next line
+ QObject::connect(pProtocolDialog.get(), &IProtocolDialog::closing,
+ this, [this]() { pProtocolDialog = nullptr; });
+}
+
+void main_window::show_filter_settings()
+{
+ if (mk_dialog(current_filter(), pFilterDialog) && work && work->libs.pFilter)
+ pFilterDialog->register_filter(work->libs.pFilter.get());
+ if (pFilterDialog)
+ // must run bundle::reload(), don't remove next line
+ QObject::connect(pFilterDialog.get(), &IFilterDialog::closing,
+ this, [this]() { pFilterDialog = nullptr; });
+}
+
+void main_window::show_options_dialog()
+{
+ if (mk_window(options_widget, [&](bool flag) { set_keys_enabled(!flag); }))
+ {
+ connect(options_widget.get(), &options_dialog::closing,
+ this, &main_window::register_shortcuts);
+ }
+}
+
+void main_window::show_mapping_window()
+{
+ mk_window(mapping_widget, pose);
+}
+
+void main_window::exit(int status)
+{
+ QApplication::setQuitOnLastWindowClosed(true);
+ if (tray)
+ tray->hide();
+ tray = nullptr;
+ close();
+ QApplication::exit(status);
+}
+
+bool main_window::set_profile(const QString& new_name_)
+{
+ if (!refresh_config_list())
+ return false;
+
+ QString new_name = new_name_;
+
+ if (!is_config_listed(new_name))
+ new_name = OPENTRACK_DEFAULT_CONFIG_Q;
+
+ if (maybe_die_on_config_not_writable(new_name, nullptr))
+ return false;
+
+ ui.iconcomboProfile->setCurrentText(new_name);
+ set_profile_in_registry(new_name);
+
+ set_title();
+ options::detail::bundler::refresh_all_bundles();
+
+ // migrations are for config layout changes and other user-visible
+ // incompatibilities in future versions
+ run_migrations();
+
+ return true;
+}
+
+void main_window::ensure_tray()
+{
+ if (!QSystemTrayIcon::isSystemTrayAvailable())
+ {
+ QApplication::setQuitOnLastWindowClosed(true);
+ return;
+ }
+
+ if (s.tray_enabled)
+ {
+ if (!tray)
+ {
+ tray = std::make_unique<QSystemTrayIcon>(this);
+ tray->setIcon(QIcon(":/images/facetracknoir.png"));
+ tray->setContextMenu(&tray_menu);
+ tray->show();
+
+ connect(tray.get(),
+ &QSystemTrayIcon::activated,
+ this,
+ &main_window::toggle_restore_from_tray);
+ }
+
+ QApplication::setQuitOnLastWindowClosed(false);
+ }
+ else
+ {
+ const bool is_hidden = isHidden() || !isVisible();
+
+ if (is_hidden)
+ {
+ show();
+ setVisible(true);
+
+ raise(); // for OSX
+ activateWindow(); // for Windows
+ }
+
+ if (tray)
+ tray->hide();
+ tray = nullptr;
+
+ QApplication::setQuitOnLastWindowClosed(true);
+ }
+}
+
+void main_window::toggle_restore_from_tray(QSystemTrayIcon::ActivationReason e)
+{
+ if (progn(
+ switch (e)
+ {
+ // if we enable double click also then it causes
+ // toggle back to the original state
+ //case QSystemTrayIcon::DoubleClick:
+ case QSystemTrayIcon::Trigger: // single click
+ return false;
+ default:
+ return true;
+ }
+ ))
+ {
+ return;
+ }
+
+ ensure_tray();
+
+ const bool is_minimized = isHidden() || !is_tray_enabled();
+
+ menu_action_show.setText(!isHidden() ? tr("Show the Octopus") : tr("Hide the Octopus"));
+
+ setVisible(is_minimized);
+ setHidden(!is_minimized);
+
+ setWindowState(progn(
+ using ws = Qt::WindowStates;
+ if (is_minimized)
+ return ws(windowState() & (~Qt::WindowMinimized));
+ else
+ return ws(Qt::WindowNoState);
+ ));
+
+ if (is_minimized)
+ {
+ raise(); // for OSX
+ activateWindow(); // for Windows
+ }
+ else
+ {
+ lower();
+ clearFocus();
+ }
+}
+
+bool main_window::maybe_hide_to_tray(QEvent* e)
+{
+ if (e->type() == QEvent::WindowStateChange &&
+ (windowState() & Qt::WindowMinimized) &&
+ is_tray_enabled())
+ {
+ e->accept();
+ ensure_tray();
+ hide();
+
+ return true;
+ }
+
+ return false;
+}
+
+void main_window::maybe_start_profile_from_executable()
+{
+ if (!work)
+ {
+ QString prof;
+ if (det.config_to_start(prof))
+ {
+ ui.iconcomboProfile->setCurrentText(prof);
+ start_tracker_();
+ }
+ }
+ else
+ {
+ if (det.should_stop())
+ stop_tracker_();
+ }
+}
+
+void main_window::set_keys_enabled(bool flag)
+{
+ if (!flag)
+ {
+ if (work)
+ work->sc->reload({});
+ global_shortcuts.reload({});
+ }
+ else
+ {
+ register_shortcuts();
+ }
+}
+
+bool main_window::is_config_listed(const QString& name)
+{
+ const int sz = ui.iconcomboProfile->count();
+ for (int i = 0; i < sz; i++)
+ if (ui.iconcomboProfile->itemText(i) == name)
+ return true;
+ return false;
+}
+
+void main_window::changeEvent(QEvent* e)
+{
+ if (!maybe_hide_to_tray(e))
+ e->ignore();
+}
+
+void main_window::closeEvent(QCloseEvent* ev)
+{
+ if (tray && tray->isVisible())
+ {
+ ev->ignore();
+ setVisible(false);
+ }
+ else
+ {
+ ev->accept();
+ }
+}
+
+bool main_window::event(QEvent* event)
+{
+ using t = QEvent::Type;
+
+ if (work)
+ {
+ switch (event->type())
+ {
+ case t::Hide:
+ case t::WindowActivate:
+ case t::WindowDeactivate:
+ case t::WindowStateChange:
+ case t::FocusIn:
+ set_is_visible(*this, true);
+ /*FALLTHROUGH*/
+ default:
+ break;
+ }
+ }
+ return QMainWindow::event(event);
+}
+
+bool main_window::is_tray_enabled()
+{
+ return s.tray_enabled && QSystemTrayIcon::isSystemTrayAvailable();
+}
+
+bool main_window::start_in_tray()
+{
+ return s.tray_enabled && s.tray_start && QSystemTrayIcon::isSystemTrayAvailable();
+}
+
+void main_window::set_profile_in_registry(const QString &profile)
+{
+ group::with_global_settings_object([&](QSettings& s) {
+ s.setValue(OPENTRACK_CONFIG_FILENAME_KEY, profile);
+ });
+}
diff --git a/variant/default/main-window.hpp b/variant/default/main-window.hpp
new file mode 100644
index 00000000..844542f1
--- /dev/null
+++ b/variant/default/main-window.hpp
@@ -0,0 +1,158 @@
+/* Copyright (c) 2013-2016, 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 "api/plugin-support.hpp"
+#include "gui/mapping-dialog.hpp"
+#include "gui/settings.hpp"
+#include "gui/process_detector.h"
+#include "logic/main-settings.hpp"
+#include "logic/pipeline.hpp"
+#include "logic/shortcuts.h"
+#include "logic/work.hpp"
+#include "logic/state.hpp"
+#include "options/options.hpp"
+
+#include <QApplication>
+#include <QMainWindow>
+#include <QKeySequence>
+#include <QShortcut>
+#include <QPixmap>
+#include <QTimer>
+#include <QSystemTrayIcon>
+#include <QString>
+#include <QMenu>
+#include <QAction>
+#include <QEvent>
+#include <QCloseEvent>
+
+#include <vector>
+#include <tuple>
+#include <memory>
+
+#include "gui/ui_main-window.h"
+
+using namespace options;
+
+class main_window : public QMainWindow, private State
+{
+ Q_OBJECT
+
+ Ui::main_window ui;
+
+ Shortcuts global_shortcuts;
+ module_settings m;
+ std::unique_ptr<QSystemTrayIcon> tray;
+ QMenu tray_menu;
+ QTimer pose_update_timer { this };
+ QTimer det_timer;
+ QTimer config_list_timer;
+ std::unique_ptr<options_dialog> options_widget;
+ std::unique_ptr<mapping_dialog> mapping_widget;
+ QShortcut kbd_quit { QKeySequence("Ctrl+Q"), this };
+ std::unique_ptr<IFilterDialog> pFilterDialog;
+ std::unique_ptr<IProtocolDialog> pProtocolDialog;
+ std::unique_ptr<ITrackerDialog> pTrackerDialog;
+
+ process_detector_worker det;
+ QMenu profile_menu;
+
+ QAction menu_action_header { &tray_menu },
+ menu_action_show { &tray_menu },
+ menu_action_exit { &tray_menu },
+ menu_action_tracker { &tray_menu },
+ menu_action_filter { &tray_menu },
+ menu_action_proto { &tray_menu },
+ menu_action_options { &tray_menu },
+ menu_action_mappings { &tray_menu };
+
+ std::shared_ptr<dylib> current_tracker()
+ {
+ return modules.trackers().value(ui.iconcomboTrackerSource->currentIndex(), nullptr);
+ }
+ std::shared_ptr<dylib> current_protocol()
+ {
+ return modules.protocols().value(ui.iconcomboProtocol->currentIndex(), nullptr);
+ }
+ std::shared_ptr<dylib> current_filter()
+ {
+ return modules.filters().value(ui.iconcomboFilter->currentIndex(), nullptr);
+ }
+
+ void update_button_state(bool running, bool inertialp);
+ void display_pose(const double* mapped, const double* raw);
+ void set_title(const QString& game_title = QStringLiteral(""));
+ static bool get_new_config_name_from_dialog(QString &ret);
+ void set_profile_in_registry(const QString& profile);
+ void register_shortcuts();
+ void set_keys_enabled(bool flag);
+ bool is_config_listed(const QString& name);
+
+ void init_tray();
+
+ void changeEvent(QEvent* e) override;
+ void closeEvent(QCloseEvent* ev) override;
+ bool event(QEvent *event) override;
+ bool maybe_hide_to_tray(QEvent* e);
+#if !defined _WIN32 && !defined __APPLE__
+ void annoy_if_root();
+#endif
+
+ // only use in impl file since no definition in header!
+ template<typename t>
+ bool mk_dialog(std::shared_ptr<dylib> lib, std::unique_ptr<t>& d);
+
+ // idem
+ template<typename t, typename... Args>
+ inline bool mk_window(std::unique_ptr<t>& place, Args&&... params);
+
+ // idem
+ template<typename t, typename F>
+ bool mk_window_common(std::unique_ptr<t>& d, F&& ctor);
+
+private slots:
+ void save_modules();
+ void exit(int status = EXIT_SUCCESS);
+ bool set_profile(const QString& new_name);
+
+ void show_tracker_settings();
+ void show_proto_settings();
+ void show_filter_settings();
+ void show_options_dialog();
+ void show_mapping_window();
+ void show_pose();
+
+ void maybe_start_profile_from_executable();
+
+ void make_empty_config();
+ void make_copied_config();
+ void open_config_directory();
+ bool refresh_config_list();
+
+ void start_tracker_();
+ void stop_tracker_();
+
+ void ensure_tray();
+
+ void toggle_restore_from_tray(QSystemTrayIcon::ActivationReason e);
+
+signals:
+ void start_tracker();
+ void stop_tracker();
+ void toggle_tracker();
+ void restart_tracker();
+public:
+ main_window();
+ ~main_window();
+ static void set_working_directory();
+ bool maybe_die_on_config_not_writable(const QString& current, QStringList* ini_list);
+ void die_on_config_not_writable();
+ bool is_tray_enabled();
+ bool start_in_tray();
+};
diff --git a/variant/default/main-window.ui b/variant/default/main-window.ui
new file mode 100644
index 00000000..ce8e161f
--- /dev/null
+++ b/variant/default/main-window.ui
@@ -0,0 +1,1453 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <author>Lovecraftian Octopus</author>
+ <class>main_window</class>
+ <widget class="QMainWindow" name="main_window">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>651</width>
+ <height>499</height>
+ </rect>
+ </property>
+ <property name="windowIcon">
+ <iconset resource="opentrack-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="QHBoxLayout" name="horizontalLayout_5">
+ <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>6</number>
+ </property>
+ <property name="bottomMargin">
+ <number>6</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="QVBoxLayout" name="verticalLayout_5">
+ <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="top">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <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>4</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>320</width>
+ <height>240</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>320</width>
+ <height>240</height>
+ </size>
+ </property>
+ <widget class="QFrame" name="video_frame">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>320</width>
+ <height>240</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>320</width>
+ <height>240</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>320</width>
+ <height>240</height>
+ </size>
+ </property>
+ <widget class="QLabel" name="video_frame_label">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>320</width>
+ <height>240</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>320</width>
+ <height>240</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>320</width>
+ <height>240</height>
+ </size>
+ </property>
+ <property name="font">
+ <font>
+ <family>Candara</family>
+ <pointsize>37</pointsize>
+ <weight>50</weight>
+ <bold>false</bold>
+ <kerning>true</kerning>
+ </font>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="pixmap">
+ <pixmap resource="opentrack-res.qrc">:/images/tracking-not-started.png</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <widget class="pose_widget" name="pose_display" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>320</width>
+ <height>240</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QFrame" name="top_display">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="lineWidth">
+ <number>0</number>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="leftMargin">
+ <number>5</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="box_raw_headpose">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>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="spacing">
+ <number>0</number>
+ </property>
+ <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="font">
+ <font>
+ <stylestrategy>NoAntialias</stylestrategy>
+ <kerning>false</kerning>
+ </font>
+ </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="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>Z</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="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="font">
+ <font>
+ <stylestrategy>NoAntialias</stylestrategy>
+ <kerning>false</kerning>
+ </font>
+ </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>Y</string>
+ </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>X</string>
+ </property>
+ </widget>
+ </item>
+ <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="font">
+ <font>
+ <stylestrategy>NoAntialias</stylestrategy>
+ <kerning>false</kerning>
+ </font>
+ </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="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="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="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="font">
+ <font>
+ <stylestrategy>NoAntialias</stylestrategy>
+ <kerning>false</kerning>
+ </font>
+ </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="font">
+ <font>
+ <stylestrategy>NoAntialias</stylestrategy>
+ <kerning>false</kerning>
+ </font>
+ </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="font">
+ <font>
+ <stylestrategy>NoAntialias</stylestrategy>
+ <kerning>false</kerning>
+ </font>
+ </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>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="box_mapped_headpose">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>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="spacing">
+ <number>0</number>
+ </property>
+ <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="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <stylestrategy>NoAntialias</stylestrategy>
+ <kerning>false</kerning>
+ </font>
+ </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="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <stylestrategy>NoAntialias</stylestrategy>
+ <kerning>false</kerning>
+ </font>
+ </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="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <stylestrategy>NoAntialias</stylestrategy>
+ <kerning>false</kerning>
+ </font>
+ </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="0">
+ <widget class="QLabel" name="lblx">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <property name="text">
+ <string>X</string>
+ </property>
+ </widget>
+ </item>
+ <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="Maximum">
+ <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>Y</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="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <stylestrategy>NoAntialias</stylestrategy>
+ <kerning>false</kerning>
+ </font>
+ </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="2">
+ <widget class="QLabel" name="lblRotY_2">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
+ <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="2" column="2">
+ <widget class="QLabel" name="lblRotZ_2">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
+ <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="2">
+ <widget class="QLabel" name="lblRotX_2">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
+ <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="0">
+ <widget class="QLabel" name="lblZ_2">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
+ <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>Z</string>
+ </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="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <stylestrategy>NoAntialias</stylestrategy>
+ <kerning>false</kerning>
+ </font>
+ </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="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <stylestrategy>NoAntialias</stylestrategy>
+ <kerning>false</kerning>
+ </font>
+ </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>
+ <item>
+ <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>6</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>6</number>
+ </property>
+ <item row="0" column="1">
+ <widget class="QFrame" name="groupWindows">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>4</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="lineWidth">
+ <number>0</number>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <property name="spacing">
+ <number>3</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="groupProfile">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <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="QToolButton" name="profile_button">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="focusPolicy">
+ <enum>Qt::StrongFocus</enum>
+ </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="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="focusPolicy">
+ <enum>Qt::StrongFocus</enum>
+ </property>
+ <property name="maxVisibleItems">
+ <number>20</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="btnShortcuts">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Options</string>
+ </property>
+ <property name="icon">
+ <iconset resource="opentrack-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>
+ <item>
+ <widget class="QPushButton" name="btnEditCurves">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Mapping</string>
+ </property>
+ <property name="icon">
+ <iconset resource="opentrack-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="QGroupBox" name="groupStartStop">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>3</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Tracking</string>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <property name="spacing">
+ <number>8</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>6</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QToolButton" name="btnStartTracker">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </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="Minimum" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Stop</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QFrame" name="frame_2">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>4</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>2</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>2</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>8</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="groupTrackerSource">
+ <property name="title">
+ <string>Input</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <property name="leftMargin">
+ <number>4</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>0</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QComboBox" name="iconcomboTrackerSource">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="focusPolicy">
+ <enum>Qt::TabFocus</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QToolButton" name="btnShowEngineControls">
+ <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="font">
+ <font>
+ <family>DejaVu Sans</family>
+ <stylestrategy>PreferAntialias</stylestrategy>
+ <kerning>false</kerning>
+ </font>
+ </property>
+ <property name="focusPolicy">
+ <enum>Qt::ClickFocus</enum>
+ </property>
+ <property name="text">
+ <string>🔨</string>
+ </property>
+ <property name="flat" stdset="0">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupGameProtocol">
+ <property name="title">
+ <string>Output</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>0</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">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="focusPolicy">
+ <enum>Qt::TabFocus</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QToolButton" name="btnShowServerControls">
+ <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="font">
+ <font>
+ <family>DejaVu Sans</family>
+ <stylestrategy>PreferAntialias</stylestrategy>
+ <kerning>false</kerning>
+ </font>
+ </property>
+ <property name="focusPolicy">
+ <enum>Qt::ClickFocus</enum>
+ </property>
+ <property name="text">
+ <string>🔨</string>
+ </property>
+ <property name="flat" stdset="0">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupFilter">
+ <property name="title">
+ <string>Filter</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_3">
+ <property name="leftMargin">
+ <number>4</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>0</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QComboBox" name="iconcomboFilter">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="focusPolicy">
+ <enum>Qt::TabFocus</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QToolButton" name="btnShowFilterControls">
+ <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="font">
+ <font>
+ <family>DejaVu Sans</family>
+ <stylestrategy>PreferAntialias</stylestrategy>
+ <kerning>false</kerning>
+ </font>
+ </property>
+ <property name="focusPolicy">
+ <enum>Qt::ClickFocus</enum>
+ </property>
+ <property name="text">
+ <string>🔨</string>
+ </property>
+ <property name="flat" stdset="0">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>pose_widget</class>
+ <extends>QWidget</extends>
+ <header>pose-widget/pose-widget.hpp</header>
+ </customwidget>
+ </customwidgets>
+ <tabstops>
+ <tabstop>btnStartTracker</tabstop>
+ <tabstop>btnStopTracker</tabstop>
+ <tabstop>profile_button</tabstop>
+ <tabstop>iconcomboProfile</tabstop>
+ <tabstop>btnShortcuts</tabstop>
+ <tabstop>btnEditCurves</tabstop>
+ </tabstops>
+ <resources>
+ <include location="opentrack-res.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/variant/default/main.cpp b/variant/default/main.cpp
index e539c635..3ee93422 100644
--- a/variant/default/main.cpp
+++ b/variant/default/main.cpp
@@ -1,5 +1,5 @@
#include "gui/init.hpp"
-#include "gui/main-window.hpp"
+#include "main-window.hpp"
#if defined _WIN32
# include <windows.h>
diff --git a/variant/default/new_config.ui b/variant/default/new_config.ui
new file mode 100644
index 00000000..27dce0f8
--- /dev/null
+++ b/variant/default/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/variant/default/new_file_dialog.cpp b/variant/default/new_file_dialog.cpp
new file mode 100644
index 00000000..831fe63e
--- /dev/null
+++ b/variant/default/new_file_dialog.cpp
@@ -0,0 +1,39 @@
+#pragma once
+
+#include "new_file_dialog.h"
+
+new_file_dialog::new_file_dialog(QWidget* parent) : QDialog(parent)
+{
+ ui.setupUi(this);
+ connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(ok_clicked()));
+ connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(cancel_clicked()));
+ setFixedSize(size());
+}
+
+bool new_file_dialog::is_ok(QString& name_)
+{
+ name_ = name;
+ return ok;
+}
+
+void new_file_dialog::cancel_clicked() { close(); }
+
+void new_file_dialog::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,
+ tr("File exists"),
+ tr("This file already exists. Pick another name."),
+ QMessageBox::Ok, QMessageBox::NoButton);
+ return;
+ }
+ ok = true;
+ close();
+ name = text;
+}
diff --git a/variant/default/new_file_dialog.h b/variant/default/new_file_dialog.h
new file mode 100644
index 00000000..5669e4a9
--- /dev/null
+++ b/variant/default/new_file_dialog.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "ui_new_config.h"
+#include "options/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);
+ bool is_ok(QString& name_);
+
+private:
+ Ui::UI_new_config ui;
+ bool ok = false;
+ QString name;
+
+private slots:
+ void cancel_clicked();
+ void ok_clicked();
+};