Add dead-zone controls to UI, v2.6.4

This commit is contained in:
wheaney 2026-01-21 10:59:14 -08:00
parent e96ccc4f0b
commit 3fc4dcefd9
10 changed files with 141 additions and 12 deletions

View File

@ -1 +1 @@
2.6.3
2.6.4

View File

@ -594,18 +594,17 @@ export const VirtualDisplayEffect = GObject.registerClass({
this.set_uniform_float(this.get_uniform_location('u_look_ahead_ms'), 1, [0.0]);
lookAheadSet = true;
}
let posePositionPixels = [0.0, 0.0, 0.0];
if (this.pose_has_position) {
posePositionPixels = this.imu_snapshots.pose_position.map((coord, index) => {
return coord * this.fov_details.fullScreenDistancePixels + this.lens_vector[index];
});
}
this.set_uniform_matrix(this.get_uniform_location("u_pose_orientation"), false, 4, this.imu_snapshots.pose_orientation);
this.set_uniform_float(this.get_uniform_location("u_pose_position"), 3, posePositionPixels);
} else {
this.set_uniform_matrix(this.get_uniform_location("u_pose_orientation"), false, 4, this.imu_snapshots.smooth_follow_origin);
this.set_uniform_float(this.get_uniform_location("u_pose_position"), 3, [0.0, 0.0, 0.0]);
}
let posePositionPixels = [0.0, 0.0, 0.0];
if (this.pose_has_position) {
posePositionPixels = this.imu_snapshots.pose_position.map((coord, index) => {
return coord * this.fov_details.fullScreenDistancePixels + this.lens_vector[index];
});
}
this.set_uniform_float(this.get_uniform_location("u_pose_position"), 3, posePositionPixels);
if (!lookAheadSet) {
this.set_uniform_float(this.get_uniform_location('u_look_ahead_ms'), 1, [lookAheadMS(this.imu_snapshots.timestamp_ms, Globals.data_stream.device_data.lookAheadCfg, this.look_ahead_override)]);
}

View File

@ -372,6 +372,12 @@ BreezyDesktopEffectConfig::BreezyDesktopEffectConfig(QObject *parent, const KPlu
connect(ui.SmoothFollowTrackRoll, &QCheckBox::toggled, this, &BreezyDesktopEffectConfig::updateSmoothFollowTrackRoll);
connect(ui.NeckSaverHorizontalMultiplier, &QSlider::valueChanged, this, &BreezyDesktopEffectConfig::updateNeckSaverHorizontal);
connect(ui.NeckSaverVerticalMultiplier, &QSlider::valueChanged, this, &BreezyDesktopEffectConfig::updateNeckSaverVertical);
connect(ui.DeadZoneThresholdDeg, &QSlider::valueChanged, this, &BreezyDesktopEffectConfig::updateDeadZoneThresholdDeg);
if (ui.DeadZoneThresholdDeg) {
ui.DeadZoneThresholdDeg->setValueUnitsSuffix(QStringLiteral("°"));
ui.DeadZoneThresholdDeg->setValueText(0, i18n("Disabled"));
}
if (auto label = widget()->findChild<QLabel*>("labelAppNameVersion")) {
label->setText(QStringLiteral("Breezy Desktop - v%1").arg(QLatin1String(BREEZY_DESKTOP_VERSION_STR)));
@ -763,6 +769,12 @@ void BreezyDesktopEffectConfig::pollDriverState()
ui.NeckSaverVerticalMultiplier->setValue(vertInt);
}
const double dz = deadZoneThresholdDeg(configJsonOpt);
const int dzInt = static_cast<int>(std::round(dz * 10.0));
if (ui.DeadZoneThresholdDeg->value() != dzInt) {
ui.DeadZoneThresholdDeg->setValue(dzInt);
}
refreshLicenseUi(stateJson);
m_driverStateInitialized = true;
@ -836,6 +848,16 @@ double BreezyDesktopEffectConfig::neckSaverVerticalMultiplier(std::optional<QJso
return v;
}
double BreezyDesktopEffectConfig::deadZoneThresholdDeg(std::optional<QJsonObject> configJsonOpt)
{
if (!configJsonOpt) return 0.0;
const QJsonValue jv = configJsonOpt->value(QStringLiteral("dead_zone_threshold_deg"));
const double v = jv.isDouble() ? jv.toDouble() : 0.0;
if (v < 0.0) return 0.0;
if (v > 5.0) return 5.0;
return v;
}
void BreezyDesktopEffectConfig::updateNeckSaverHorizontal()
{
auto configJsonOpt = XRDriverIPC::instance().retrieveConfig();
@ -858,6 +880,20 @@ void BreezyDesktopEffectConfig::updateNeckSaverVertical()
XRDriverIPC::instance().writeConfig(newConfig);
}
void BreezyDesktopEffectConfig::updateDeadZoneThresholdDeg()
{
auto configJsonOpt = XRDriverIPC::instance().retrieveConfig();
double val = ui.DeadZoneThresholdDeg->value() / 10.0;
val = std::clamp(val, 0.0, 5.0);
const double current = deadZoneThresholdDeg(configJsonOpt);
if (std::abs(current - val) < 1e-9) return;
QJsonObject newConfig = configJsonOpt ? configJsonOpt.value() : QJsonObject();
newConfig.insert(QStringLiteral("dead_zone_threshold_deg"), val);
XRDriverIPC::instance().writeConfig(newConfig);
}
bool BreezyDesktopEffectConfig::multitapEnabled(std::optional<QJsonObject> configJsonOpt)
{
if (!configJsonOpt) return false;

View File

@ -39,6 +39,7 @@ private:
void updateSmoothFollowTrackRoll();
void updateNeckSaverHorizontal();
void updateNeckSaverVertical();
void updateDeadZoneThresholdDeg();
void updateUiFromConfig();
void updateUiFromDefaultConfig();
void updateConfigFromUi();
@ -51,6 +52,7 @@ private:
bool smoothFollowTrackRollEnabled(std::optional<QJsonObject> configJsonOpt);
double neckSaverHorizontalMultiplier(std::optional<QJsonObject> configJsonOpt);
double neckSaverVerticalMultiplier(std::optional<QJsonObject> configJsonOpt);
double deadZoneThresholdDeg(std::optional<QJsonObject> configJsonOpt);
void pollDriverState();
void refreshLicenseUi(const QJsonObject &rootObj);
void checkEffectLoaded();

View File

@ -654,13 +654,48 @@
</widget>
</item>
<item row="13" column="0">
<widget class="QLabel" name="labelDeadZoneThresholdDeg">
<property name="text">
<string>Dead-zone threshold (deg):</string>
</property>
</widget>
</item>
<item row="13" column="1">
<widget class="LabeledSlider" name="DeadZoneThresholdDeg">
<property name="decimalShift">
<double>1</double>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>50</number>
</property>
<property name="tickStartOffset">
<double>0</double>
</property>
<property name="tickInterval">
<double>10</double>
</property>
<property name="tickPosition">
<enum>QSlider::NoTicks</enum>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tracking">
<bool>false</bool>
</property>
</widget>
</item>
<item row="14" column="0">
<widget class="QLabel" name="labelMeasurementUnits">
<property name="text">
<string>Measurement units:</string>
</property>
</widget>
</item>
<item row="13" column="1">
<item row="14" column="1">
<widget class="QComboBox" name="comboMeasurementUnits"/>
</item>
</layout>

@ -1 +1 @@
Subproject commit b74587dfc17e85c63ee03fdbdd8f2541400f454f
Subproject commit 4267946ef0d0d24a7563455c70b8cee6bcd1f2da

@ -1 +1 @@
Subproject commit 44657a5de6532ac0ec1a4ce6d3ccd73e2c87fdc6
Subproject commit 6f1844829e11fcc7664398d4c95d8fbdb6341669

View File

@ -10,6 +10,13 @@ class ConfigManager(GObject.GObject):
'follow-track-roll': (bool, 'Follow Track Roll', 'Whether to follow on the roll axis', False, GObject.ParamFlags.READWRITE),
'follow-track-pitch': (bool, 'Follow Track Pitch', 'Whether to follow on the pitch axis', True, GObject.ParamFlags.READWRITE),
'follow-track-yaw': (bool, 'Follow Track Yaw', 'Whether to follow on the yaw axis', True, GObject.ParamFlags.READWRITE),
'dead-zone-threshold-deg': (
float,
'Dead Zone Threshold (deg)',
'IMU dead-zone threshold in degrees (0.0 disables)',
0.0, 5.0, 0.0,
GObject.ParamFlags.READWRITE,
),
'neck-saver-horizontal-multiplier': (
float,
'Neck Saver Horizontal Multiplier',
@ -49,6 +56,7 @@ class ConfigManager(GObject.GObject):
self.follow_track_roll = None
self.follow_track_pitch = None
self.follow_track_yaw = None
self.dead_zone_threshold_deg = None
self.neck_saver_horizontal_multiplier = None
self.neck_saver_vertical_multiplier = None
self._running = True
@ -74,6 +82,9 @@ class ConfigManager(GObject.GObject):
if self.config['smooth_follow_track_yaw'] != self.follow_track_yaw:
self.set_property('follow-track-yaw', self.config['smooth_follow_track_yaw'])
if self.config['dead_zone_threshold_deg'] != self.dead_zone_threshold_deg:
self.set_property('dead-zone-threshold-deg', self.config['dead_zone_threshold_deg'])
if self.config['neck_saver_horizontal_multiplier'] != self.neck_saver_horizontal_multiplier:
self.set_property('neck-saver-horizontal-multiplier', self.config['neck_saver_horizontal_multiplier'])
@ -120,6 +131,13 @@ class ConfigManager(GObject.GObject):
self.ipc.write_config(self.config)
self.follow_track_yaw = value
def _set_dead_zone_threshold_deg(self, value):
value = round(min(5.0, max(0.0, float(value))), 2)
if self.dead_zone_threshold_deg != value:
self.config['dead_zone_threshold_deg'] = value
self.ipc.write_config(self.config)
self.dead_zone_threshold_deg = value
def _set_neck_saver_horizontal_multiplier(self, value):
value = round(min(2.5, max(1.0, float(value))), 2)
if self.neck_saver_horizontal_multiplier != value:
@ -145,6 +163,8 @@ class ConfigManager(GObject.GObject):
self._set_follow_track_pitch(value)
elif prop.name == 'follow-track-yaw':
self._set_follow_track_yaw(value)
elif prop.name == 'dead-zone-threshold-deg':
self._set_dead_zone_threshold_deg(value)
elif prop.name == 'neck-saver-horizontal-multiplier':
self._set_neck_saver_horizontal_multiplier(value)
elif prop.name == 'neck-saver-vertical-multiplier':
@ -161,6 +181,8 @@ class ConfigManager(GObject.GObject):
return self.follow_track_pitch
elif prop.name == 'follow-track-yaw':
return self.follow_track_yaw
elif prop.name == 'dead-zone-threshold-deg':
return self.dead_zone_threshold_deg
elif prop.name == 'neck-saver-horizontal-multiplier':
return self.neck_saver_horizontal_multiplier
elif prop.name == 'neck-saver-vertical-multiplier':

View File

@ -73,6 +73,8 @@ class ConnectedDevice(Gtk.Box):
neck_saver_horizontal_adjustment = Gtk.Template.Child()
neck_saver_vertical_scale = Gtk.Template.Child()
neck_saver_vertical_adjustment = Gtk.Template.Child()
dead_zone_threshold_scale = Gtk.Template.Child()
dead_zone_threshold_adjustment = Gtk.Template.Child()
enable_multi_tap_switch = Gtk.Template.Child()
legacy_follow_mode_switch = Gtk.Template.Child()
follow_track_yaw_switch = Gtk.Template.Child()
@ -193,6 +195,7 @@ class ConnectedDevice(Gtk.Box):
self._bind_switch_to_config(self.follow_track_roll_switch, 'follow-track-roll')
self._bind_switch_to_config(self.follow_track_pitch_switch, 'follow-track-pitch')
self._bind_switch_to_config(self.follow_track_yaw_switch, 'follow-track-yaw')
self._bind_scale_to_config(self.dead_zone_threshold_adjustment, 'dead-zone-threshold-deg')
self._bind_scale_to_config(self.neck_saver_horizontal_adjustment, 'neck-saver-horizontal-multiplier')
self._bind_scale_to_config(self.neck_saver_vertical_adjustment, 'neck-saver-vertical-multiplier')

View File

@ -762,6 +762,38 @@
</child>
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Dead-zone threshold (degrees)</property>
<property name="subtitle" translatable="yes">Stabilize movements below this angle.</property>
<child>
<object class="GtkScale" id="dead_zone_threshold_scale">
<property name="valign">3</property>
<property name="draw-value">true</property>
<property name="value-pos">0</property>
<property name="digits">1</property>
<property name="width-request">350</property>
<property name="has-origin">false</property>
<property name="adjustment">
<object class="GtkAdjustment" id="dead_zone_threshold_adjustment">
<property name="lower">0.0</property>
<property name="upper">5.0</property>
<property name="step-increment">0.1</property>
<property name="value">0.0</property>
</object>
</property>
<marks>
<mark value="0.0" position="bottom" translatable="yes">Disabled</mark>
<mark value="1.0" position="bottom">1.0</mark>
<mark value="2.0" position="bottom">2.0</mark>
<mark value="3.0" position="bottom">3.0</mark>
<mark value="4.0" position="bottom">4.0</mark>
<mark value="5.0" position="bottom">5.0</mark>
</marks>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Follow mode movement tracking</property>