Skip to content

Expose single-click/double-click discrimination interval as a user-adjustable setting #3009

Description

@ten9876

Background

Several widgets across the app use QApplication::doubleClickInterval() (typically 400 ms on Linux, configurable per-platform) to defer single-click actions long enough to detect a double-click. Most prominent example: the RX Controls 🔊 mute button (PR #3006), where single click mutes the current slice and double click mutes all owned slices. The single-click action waits the full interval before firing, so the user perceives ~400 ms of latency on every single click.

Power users who never double-click would prefer instant single-click response; users with slower motor input may want a longer window to reliably register their double-click intent. Right now it's bound to the platform default with no escape hatch.

Call sites today

Found via grep — every widget that uses the click-defer pattern:

All seven currently call QApplication::doubleClickInterval() directly. The values would diverge if a future widget uses a different source — making them all read the same project-wide value also closes that risk.

Proposed shape

1. New AppSettings key

ClickDiscriminationIntervalMs (int, default = QApplication::doubleClickInterval())

Range bounds worth picking: minimum ~150 ms (faster than human double-click capability), maximum ~800 ms (anything more starts to feel broken on single-click). 0 is reserved for "no double-click discrimination — fire single-click instantly" which intentionally disables any double-click affordance app-wide.

2. Helper accessor

Add a one-liner in a shared location (probably AppSettings.h or a small InteractionSettings.h):

inline int clickDiscriminationIntervalMs()
{
    auto& s = AppSettings::instance();
    return s.value("ClickDiscriminationIntervalMs",
                   QApplication::doubleClickInterval()).toInt();
}

3. Migrate all seven call sites

Replace every QApplication::doubleClickInterval() call with the helper. Mechanical sweep, no behavior change for users who don't touch the setting.

4. UI surface

Radio Setup → "Behavior" tab (or equivalent) — a spinbox labeled "Single-click delay (ms)" with a hint like:

Time AetherSDR waits after a single click to decide whether you intended a double click. Default uses your OS setting (currently ms). Set 0 to disable double-click affordances entirely and fire single-click actions instantly.

5. Live propagation

Some widgets (e.g. WaveformWidget) cache the interval at construction via m_clickTimer.setInterval(...). Reading the value at click time (start-from-interval-helper-each-time) instead of caching at construction means changes via Settings apply on the next click without a restart. RxApplet's pattern (m_muteClickTimer->start(clickDiscriminationIntervalMs()) at click time) already does this — the others can follow.

Why this is worth doing

  • The 400 ms single-click latency was the most-noted UX cost in PR fix(rx): consolidate slice-mute UI — single-click this slice, double-click all #3006 review. A user who never uses the double-click could set it to 0 and never feel the delay.
  • Centralizing the value protects against future widget drift.
  • The double-click vs single-click discrimination pattern will probably keep expanding (e.g. spectrum widget click-to-tune vs double-click-to-edit-frequency); having one knob is the right shape.

Acceptance

  • AppSettings key added with proper default
  • Helper accessor in a shared header
  • All seven existing call sites migrated
  • UI surface in Radio Setup
  • Tooltip on the spinbox explaining what it does
  • Manual test: set to 100, verify mute button responds quickly; set to 0, verify single click is instant and double click no longer triggers all-mute (acceptable — the user opted in)

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    GUIUser interfaceenhancementImprovement to existing featuregood first issueGood for newcomersmaintainer-reviewRequires maintainer review before any action is taken

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions