From 0c38320f1a5d38fa260cf2c7e64a43593b55bfc6 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Sun, 20 Mar 2022 19:57:22 +0200 Subject: [PATCH] Progress on the new Qt GUI --- .gitignore | 1 + Makefile.in | 11 +- README.md | 14 +- icons/devices.png | 3 + src/main.cc | 41 ++- src/spnavcfg.c | 39 +++ src/spnavcfg.h | 38 +++ src/ui.cc | 192 ++++++++++++ src/ui.h | 25 +- ui/spnavcfg.qrc | 6 + ui/spnavcfg.ui | 724 ++++++++++++++++++++++++++++++++-------------- 11 files changed, 874 insertions(+), 220 deletions(-) create mode 100644 icons/devices.png create mode 100644 src/spnavcfg.c create mode 100644 src/spnavcfg.h create mode 100644 ui/spnavcfg.qrc diff --git a/.gitignore b/.gitignore index 368e36e..b4852ca 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ Makefile spnavcfg ui_mainwin.h +res.cc diff --git a/Makefile.in b/Makefile.in index e0eed5f..9727999 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,14 +1,16 @@ +csrc = $(wildcard src/*.c) ccsrc = $(wildcard src/*.cc) mochdr = src/ui.h mocsrc = $(mochdr:.h=.moc.cc) -obj = $(ccsrc:.cc=.o) $(mocsrc:.cc=.o) -dep = $(ccsrc:.cc=.d) +obj = $(csrc:.c=.o) $(ccsrc:.cc=.o) $(mocsrc:.cc=.o) res.cc +dep = $(csrc:.c=.d) $(ccsrc:.cc=.d) bin = spnavcfg CC ?= gcc CXX ?= g++ UIC ?= uic MOC ?= moc +RCC ?= rcc warn = -pedantic -Wall incdir = -I. @@ -30,9 +32,12 @@ ui_mainwin.h: ui/spnavcfg.ui %.moc.cc: %.h $(MOC) -o $@ $(incdir) $< +res.cc: ui/spnavcfg.qrc icons/devices.png + $(RCC) -o $@ $< + .PHONY: clean clean: - rm -f $(obj) $(bin) $(mocsrc) win_main_ui.h + rm -f $(obj) $(bin) $(mocsrc) win_main_ui.h res.cc .PHONY: cleandep cleandep: diff --git a/README.md b/README.md index 2414a4d..df19bf3 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ About ----- Spacenav daemon interactive configuration program. -![shot](http://spacenav.sourceforge.net/images/spnavcfg-shot-thumb.png) +![shot](http://spacenav.sourceforge.net/images/spnavcfg1-shot-thumb.png) Compatibility @@ -29,9 +29,15 @@ which will work with older versions of the daemon is 0.3.1. Installation ------------ -Requires libspnav, GTK+ 2, and Xlib headers to be installed. -`./configure`, `make`, `make install`, as usual (the `make install` part as root -if you're installing system-wide). See `./configure --help` for build options. +First make sure you have the dependencies installed: + - libspnav v0.4 or higher + - Qt 5 (core, gui, and widgets). + +To build just run `./configure`, `make`, and `make install` as usual. +The `make install` part will probably need to be executed as root, if you're +installing system-wide. + +For build options, see `./configure --help`. License ------- diff --git a/icons/devices.png b/icons/devices.png new file mode 100644 index 0000000..9ac71a3 --- /dev/null +++ b/icons/devices.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2d1e1f4ea6ceee7a6d0793057e3535d3bd1745e2df8651c25678953e250ec310 +size 287656 diff --git a/src/main.cc b/src/main.cc index 1a05828..320ae65 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,7 +1,14 @@ #include +#include +#define SPNAV_CONFIG_H_ +#include +#include "spnavcfg.h" #include "ui.h" -QWidget *mainwin; +static bool init(); + +MainWin *mainwin; +static QSocketNotifier *sockev; int main(int argc, char **argv) { @@ -12,5 +19,37 @@ int main(int argc, char **argv) w.show(); mainwin = &w; + if(!init()) { + return 1; + } + return app.exec(); } + +static bool init() +{ + if(spnav_open() == -1) { + errorbox("Failed to connect to spacenavd!"); + return false; + } + if(spnav_protocol() < 1) { + errorbox("Currently running version of spacenavd is too old for this version of the configuration tool.\n" + "\nEither update to a recent version of spacenavd (v0.9 or later), or downgrade to spnavcfg v0.3.1."); + return false; + } + spnav_client_name("spnavcfg"); + + if(read_devinfo(&devinfo) == -1) { + errorbox("Failed to read device info."); + return false; + } + if(read_cfg(&cfg) == -1) { + errorbox("Failed to read current configuration."); + return false; + } + + sockev = new QSocketNotifier(spnav_fd(), QSocketNotifier::Read); + QObject::connect(sockev, &QSocketNotifier::activated, mainwin, &MainWin::spnav_input); + + return true; +} diff --git a/src/spnavcfg.c b/src/spnavcfg.c new file mode 100644 index 0000000..5f6b6f7 --- /dev/null +++ b/src/spnavcfg.c @@ -0,0 +1,39 @@ +#include +#include +#include "spnavcfg.h" +#include "ui.h" + +struct device_info devinfo; +struct config cfg; + +int read_devinfo(struct device_info *inf) +{ + inf->name = strdup(spnav_dev_name(0, 0)); + inf->path = strdup(spnav_dev_path(0, 0)); + inf->nbuttons = spnav_dev_buttons(); + inf->naxes = spnav_dev_axes(); + inf->type = spnav_dev_type(); +} + +int read_cfg(struct config *cfg) +{ + int i; + + cfg->sens = spnav_cfg_get_sens(); + spnav_cfg_get_axis_sens(cfg->sens_axis); + cfg->invert = spnav_cfg_get_invert(); + cfg->led = spnav_cfg_get_led(); + cfg->grab = spnav_cfg_get_grab(); + + for(i=0; i<6; i++) { + cfg->map_axis[i] = spnav_cfg_get_axismap(i); + } + for(i=0; idead_thres[i] = spnav_cfg_get_deadzone(i); + } + for(i=0; imap_bn[i] = spnav_cfg_get_bnmap(i); + } + + update_ui(); +} diff --git a/src/spnavcfg.h b/src/spnavcfg.h new file mode 100644 index 0000000..5debef0 --- /dev/null +++ b/src/spnavcfg.h @@ -0,0 +1,38 @@ +#ifndef SPNAVCFG_H_ +#define SPNAVCFG_H_ + +struct device_info { + char *name, *path; + int nbuttons, naxes; + int type; +}; + +enum {TX, TY, TZ, RX, RY, RZ}; +#define MAX_BUTTONS 64 +#define MAX_AXES 64 + +struct config { + float sens, sens_axis[6]; + int invert; + int map_axis[MAX_AXES]; + int dead_thres[MAX_AXES]; + int map_bn[MAX_BUTTONS]; + int led, grab; + int repeat; +}; + +extern struct device_info devinfo; +extern struct config cfg; + +#ifdef __cplusplus +extern "C" { +#endif + +int read_devinfo(struct device_info *inf); +int read_cfg(struct config *cfg); + +#ifdef __cplusplus +} +#endif + +#endif /* SPNAVCFG_H_ */ diff --git a/src/ui.cc b/src/ui.cc index e510830..5ed86b1 100644 --- a/src/ui.cc +++ b/src/ui.cc @@ -1,14 +1,206 @@ #include +#define SPNAV_CONFIG_H_ +#include #include "ui.h" +#include "spnavcfg.h" +#include "ui_mainwin.h" +#include + +static QSlider *slider_sens_axis[6]; +static QCheckBox *chk_inv[6]; +static QComboBox *combo_axismap[6]; +static QDoubleSpinBox *spin_sens_axis[6]; +static QSpinBox *spin_dead_axis[6]; +static QProgressBar *prog_axis[6]; +static QPixmap *dev_atlas; + + +struct device_image { + int devtype; + int width, height; + int xoffs, yoffs; +}; +static struct device_image devimglist[] = { + {SPNAV_DEV_UNKNOWN, 150, 150, 0, 0}, + {SPNAV_DEV_SB2003, 150, 150, 1, 0}, + {SPNAV_DEV_SB3003, 150, 150, 2, 0}, + {SPNAV_DEV_SB4000, 150, 150, 3, 0}, + {SPNAV_DEV_SM, 150, 150, 5, 0}, + {SPNAV_DEV_SM5000, 150, 150, 2, 0}, + {SPNAV_DEV_SMCADMAN, 150, 150, 6, 0}, + {SPNAV_DEV_PLUSXT, 150, 150, 5, 0}, + {SPNAV_DEV_CADMAN, 150, 150, 6, 0}, + {SPNAV_DEV_SMCLASSIC, 150, 150, 4, 0}, + {SPNAV_DEV_SB5000, 150, 150, 3, 0}, + {SPNAV_DEV_STRAVEL, 150, 150, 2, 1}, + {SPNAV_DEV_SPILOT, 150, 150, 3, 1}, + {SPNAV_DEV_SNAV, 150, 150, 0, 1}, + {SPNAV_DEV_SEXP, 150, 150, 4, 1}, + {SPNAV_DEV_SNAVNB, 150, 150, 1, 1}, + {SPNAV_DEV_SPILOTPRO, 150, 150, 5, 1}, + {SPNAV_DEV_SMPRO, 150, 150, 6, 1}, + {SPNAV_DEV_NULOOQ, 150, 150, 7, 0}, + {SPNAV_DEV_SMW, 150, 150, 1, 2}, + {SPNAV_DEV_SMPROW, 150, 150, 6, 1}, + {SPNAV_DEV_SMENT, 150, 150, 7, 1}, + {SPNAV_DEV_SMCOMP, 150, 150, 0, 2}, + {SPNAV_DEV_SMMOD, 150, 150, 0, 0}, + {-1} +}; + MainWin::MainWin(QWidget *par) : QWidget(par) { ui = new Ui::win_main; ui->setupUi(this); + + dev_atlas = new QPixmap(":/icons/devices.png"); + + slider_sens_axis[0] = ui->slider_sens_tx; + slider_sens_axis[1] = ui->slider_sens_ty; + slider_sens_axis[2] = ui->slider_sens_tz; + slider_sens_axis[3] = ui->slider_sens_rx; + slider_sens_axis[4] = ui->slider_sens_ry; + slider_sens_axis[5] = ui->slider_sens_rz; + + chk_inv[0] = ui->chk_inv_tx; + chk_inv[1] = ui->chk_inv_ty; + chk_inv[2] = ui->chk_inv_tz; + chk_inv[3] = ui->chk_inv_rx; + chk_inv[4] = ui->chk_inv_ry; + chk_inv[5] = ui->chk_inv_rz; + + combo_axismap[0] = ui->combo_axismap_tx; + combo_axismap[1] = ui->combo_axismap_ty; + combo_axismap[2] = ui->combo_axismap_tz; + combo_axismap[3] = ui->combo_axismap_rx; + combo_axismap[4] = ui->combo_axismap_ry; + combo_axismap[5] = ui->combo_axismap_rz; + + spin_dead_axis[0] = ui->spin_dead_tx; + spin_dead_axis[1] = ui->spin_dead_ty; + spin_dead_axis[2] = ui->spin_dead_tz; + spin_dead_axis[3] = ui->spin_dead_rx; + spin_dead_axis[4] = ui->spin_dead_ry; + spin_dead_axis[5] = ui->spin_dead_rz; + + spin_sens_axis[0] = ui->spin_sens_tx; + spin_sens_axis[1] = ui->spin_sens_ty; + spin_sens_axis[2] = ui->spin_sens_tz; + spin_sens_axis[3] = ui->spin_sens_rx; + spin_sens_axis[4] = ui->spin_sens_ry; + spin_sens_axis[5] = ui->spin_sens_rz; + + prog_axis[0] = ui->prog_tx; + prog_axis[1] = ui->prog_ty; + prog_axis[2] = ui->prog_tz; + prog_axis[3] = ui->prog_rx; + prog_axis[4] = ui->prog_ry; + prog_axis[5] = ui->prog_rz; } MainWin::~MainWin() { delete ui; + delete dev_atlas; +} + +void MainWin::updateui() +{ + struct device_image devimg = devimglist[0]; + for(int i=0; devimglist[i].devtype != -1; i++) { + if(devimglist[i].devtype == devinfo.type) { + devimg = devimglist[i]; + break; + } + } + int ncol = dev_atlas->width() / devimg.width; + int nrow = dev_atlas->height() / devimg.height; + devimg.xoffs = devimg.xoffs * dev_atlas->width() / ncol; + devimg.yoffs = devimg.yoffs * dev_atlas->height() / nrow; + + QPixmap pix = dev_atlas->copy(devimg.xoffs, devimg.yoffs, devimg.width, devimg.height); + ui->img_dev->setPixmap(pix); + + ui->lb_devname->setText(devinfo.name); + ui->lb_devfile->setText(devinfo.path); + ui->lb_numaxes->setText(QString::number(devinfo.naxes)); + ui->lb_numbn->setText(QString::number(devinfo.nbuttons)); + + ui->combo_led->setCurrentIndex(cfg.led); + ui->chk_grab->setChecked(cfg.grab); + if(cfg.repeat > 0) { + ui->chk_repeat->setChecked(true); + ui->spin_repeat->setValue(cfg.repeat); + } else { + ui->chk_repeat->setChecked(false); + } + + ui->slider_sens->setValue(cfg.sens * 10); + ui->spin_sens->setValue(cfg.sens); + for(int i=0; i<6; i++) { + slider_sens_axis[i]->setValue(cfg.sens_axis[i] * 10); + spin_sens_axis[i]->setValue(cfg.sens_axis[i]); + chk_inv[i]->setChecked((cfg.invert >> i) & 1); + + combo_axismap[i]->clear(); + for(int j=0; jaddItem(QString::number(j)); + } + for(int j=0; jsetCurrentIndex(j); + spin_dead_axis[i]->setValue(cfg.dead_thres[j]); + } + } + } + + bool same = true; + for(int i=0; i 0 && cfg.dead_thres[i] != cfg.dead_thres[i - 1]) { + same = false; + } + } + + ui->spin_dead->setValue(same ? cfg.dead_thres[0] : 0); + ui->chk_dead_global->setChecked(same); +} + +void MainWin::spnav_input() +{ + static int maxval = 256; + spnav_event ev; + + while(spnav_poll_event(&ev)) { + switch(ev.type) { + case SPNAV_EVENT_MOTION: + for(int i=0; i<6; i++) { + if(abs(ev.motion.data[i] > maxval)) maxval = abs(ev.motion.data[i]); + } + for(int i=0; i<6; i++) { + prog_axis[i]->setMinimum(-maxval); + prog_axis[i]->setMaximum(maxval); + prog_axis[i]->setValue(ev.motion.data[i]); + } + break; + + case SPNAV_EVENT_BUTTON: + // TODO + break; + + default: + break; + } + } +} + +extern "C" void update_ui(void) +{ + mainwin->updateui(); +} + +extern "C" void errorbox(const char *msg) +{ + QMessageBox::critical(mainwin, "Error", msg, QMessageBox::Ok); } diff --git a/src/ui.h b/src/ui.h index 850509f..707ab46 100644 --- a/src/ui.h +++ b/src/ui.h @@ -1,7 +1,13 @@ #ifndef UI_H_ #define UI_H_ -#include "ui_mainwin.h" +#ifdef __cplusplus + +#include + +namespace Ui { + class win_main; +} class MainWin : public QWidget { Q_OBJECT @@ -12,6 +18,23 @@ private: public: explicit MainWin(QWidget *par = 0); ~MainWin(); + + void updateui(); + +public slots: + void spnav_input(); }; +extern MainWin *mainwin; + +extern "C" { +#endif + +void update_ui(void); +void errorbox(const char *msg); + +#ifdef __cplusplus +} +#endif + #endif /* UI_H_ */ diff --git a/ui/spnavcfg.qrc b/ui/spnavcfg.qrc new file mode 100644 index 0000000..b1ab7f0 --- /dev/null +++ b/ui/spnavcfg.qrc @@ -0,0 +1,6 @@ + + + + ../icons/devices.png + + diff --git a/ui/spnavcfg.ui b/ui/spnavcfg.ui index 53bd020..be2a967 100644 --- a/ui/spnavcfg.ui +++ b/ui/spnavcfg.ui @@ -6,8 +6,8 @@ 0 0 - 816 - 650 + 800 + 667 @@ -159,12 +159,12 @@ - On + Off - Off + On @@ -295,7 +295,7 @@ - 1 + 0 @@ -327,11 +327,24 @@ + + + + 10.000000000000000 + + + 0.100000000000000 + + + Qt::Horizontal + + QSizePolicy::Preferred + 40 @@ -350,6 +363,42 @@ + + + + Qt::Horizontal + + + QSizePolicy::Preferred + + + + 40 + 20 + + + + + + + + Global deadzone + + + true + + + + + + + Deadzone for all axes + + + 255 + + + @@ -358,10 +407,72 @@ Translation - - + + + + -128 + + + 127 + + + 0 + + + false + + + %v + + + + + + + Select which device axis affects Y translation + + + + + + + Select which device axis affects X translation + + + + + + + -128 + + + 127 + + + 0 + + + false + + + %v + + + + + + + invert Y axis translation + - invert + + + + + + + + device axis @@ -372,10 +483,43 @@ - - + + + + false + + + 255 + + + + + + + invert Z axis translation + - device axis + + + + + + + + Select which device axis affects Z translation + + + + + + + Z axis translation sensitivity + + + 60 + + + Qt::Horizontal @@ -389,17 +533,14 @@ - - - - -100 - - - 24 - - + + + false + + 255 + @@ -412,66 +553,6 @@ - - - - X axis translation sensitivity - - - 60 - - - Qt::Horizontal - - - - - - - Select which device axis affects X translation - - - - - - - Select which device axis affects Y translation - - - - - - - TY - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - -100 - - - 24 - - - false - - - - - - - invert Y axis translation - - - - - - @@ -485,10 +566,62 @@ - - + + + + -128 + + + 127 + + + 0 + + + false + + + %v + + + + + + + false + + + 255 + + + + + - Select which device axis affects Z translation + X axis translation sensitivity + + + 60 + + + Qt::Horizontal + + + + + + + deadzone + + + + + + + TY + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -502,41 +635,21 @@ - - - - -100 - - - 24 - - - false - - - - - - - invert Z axis translation - + + - + invert - - - - Z axis translation sensitivity - - - 60 - - - Qt::Horizontal - - + + + + + + + + @@ -547,54 +660,10 @@ Rotation - - - - invert - - - - - - - sensitivity - - - - - - - device axis - - - - - - - RX - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - -100 - - - 24 - - - false - - - - - + + - invert X axis rotation + invert Z axis rotation @@ -614,50 +683,20 @@ - - + + Select which device axis affects X rotation - - - - Select which device axis affects Y rotation - - - - - - - RY - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - -100 - - - 24 - - + + + false - - - - - - invert Y axis rotation - - - + + 255 @@ -674,46 +713,121 @@ - - + + - Select which device axis affects Z rotation + Select which device axis affects Y rotation - - + + + + -128 + + + 127 + + + 0 + + + false + + + %v + + + + + - RZ + RY Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - + + - -100 + -128 + + + 127 - 24 + 0 false + + %v + - - + + + + invert + + + + + + + -128 + + + 127 + + + 0 + + + false + + + %v + + + + + + + false + + + 255 + + + + + - invert Z axis rotation + invert Y axis rotation + + + + sensitivity + + + + + + + device axis + + + @@ -727,6 +841,69 @@ + + + + invert X axis rotation + + + + + + + + + + RZ + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + false + + + 255 + + + + + + + deadzone + + + + + + + Select which device axis affects Z rotation + + + + + + + RX + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + @@ -736,6 +913,19 @@ Buttons + + + + 140 + 150 + 471 + 41 + + + + TODO: Button mapping, keyboard emulation, actions and so on.... + + @@ -826,5 +1016,117 @@ + + chk_dead_global + toggled(bool) + spin_dead_tx + setDisabled(bool) + + + 649 + 271 + + + 738 + 355 + + + + + chk_dead_global + toggled(bool) + spin_dead_ty + setDisabled(bool) + + + 728 + 284 + + + 747 + 393 + + + + + chk_dead_global + toggled(bool) + spin_dead_tz + setDisabled(bool) + + + 639 + 279 + + + 765 + 429 + + + + + chk_dead_global + toggled(bool) + spin_dead_rx + setDisabled(bool) + + + 622 + 280 + + + 743 + 520 + + + + + chk_dead_global + toggled(bool) + spin_dead_ry + setDisabled(bool) + + + 625 + 275 + + + 755 + 560 + + + + + chk_dead_global + toggled(bool) + spin_dead_rz + setDisabled(bool) + + + 627 + 279 + + + 769 + 599 + + + + + chk_dead_global + toggled(bool) + spin_dead + setEnabled(bool) + + + 629 + 272 + + + 760 + 277 + + +