diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2018-01-16 04:33:14 +0100 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2018-01-16 06:45:52 +0100 |
commit | 2b1c5593b0bc1ebfcd2e808f128e4b0312f59d93 (patch) | |
tree | e7e8f5d8d3af88a6df37cbd482edcbd3ff8def26 /variant/default | |
parent | 3583e3d3cd0b6ca2515ada16ca7dcc8cce83031f (diff) |
gui, variant/default: move default UI
Diffstat (limited to 'variant/default')
-rw-r--r-- | variant/default/main-window.cpp | 945 | ||||
-rw-r--r-- | variant/default/main-window.hpp | 158 | ||||
-rw-r--r-- | variant/default/main-window.ui | 1453 | ||||
-rw-r--r-- | variant/default/main.cpp | 2 | ||||
-rw-r--r-- | variant/default/new_config.ui | 45 | ||||
-rw-r--r-- | variant/default/new_file_dialog.cpp | 39 | ||||
-rw-r--r-- | variant/default/new_file_dialog.h | 25 |
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(); +}; |