Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
slider_core.hpp File Reference

The value engine shared by Pulp's continuous controls. More...

#include <algorithm>
#include <cmath>
#include <cstdint>
#include <functional>
#include <utility>
#include <vector>

Go to the source code of this file.

Classes

class  pulp::view::SliderCore

Namespaces

namespace  pulp
namespace  pulp::view
 Hover-cursor tracking for platform window hosts.

Enumerations

enum class  pulp::view::Notify { pulp::view::none , pulp::view::sync , pulp::view::async }
 Whether a value write notifies listeners, and when. More...

Functions

void pulp::view::flush_async_notifications ()
 Deferred Notify::async callbacks, oldest first.
void pulp::view::queue_async_notification (std::function< void()> fn)
 Queue a callback for the next flush.

Detailed Description

The value engine shared by Pulp's continuous controls.

A knob, a fader and a numeric field all need the same six things and none of them are about pixels:

  • a real-world range (20 .. 20000 Hz, -60 .. +12 dB), not 0..1
  • an interval the value quantizes to (1 semitone, 0.1 dB, 0 = continuous)
  • a response curve so the useful part of the range gets the travel
  • a default the control snaps back to
  • a drag law — how many pixels of pointer travel cross the range
  • notification control — whether a write fires listeners

SliderCore owns exactly that and nothing else: no bounds, no canvas, no event handling. A widget composes one and asks it to map pointer motion to value and value to travel proportion.

Two spaces

  • value — real-world units, in [minimum(), maximum()].
  • proportion — normalized travel in [0,1], what a painter turns into an angle or a thumb offset. proportion == 0 is minimum().

The response curve maps between them: proportion = normalized^skew, where normalized is the value's linear position in the range. skew == 1 is linear. skew < 1 pushes proportion UP for a given value, so the low end of the range occupies more travel — the law a frequency or time control wants. set_skew_from_midpoint(v) picks the skew that puts value v at half travel.

Notification

Every mutator takes a Notify:

  • Notify::none — change the value, fire nothing. This is what a control uses when it is being synced FROM the thing it drives (a parameter store, a preset load); firing back would be an echo, and in a two-way binding an echo is a feedback loop.
  • Notify::sync — fire on_value_change before returning (the default).
  • Notify::async — queue the callback and fire it on the next call to flush_async_notifications(), which the UI thread's frame/event pump makes. Use it when the write happens somewhere re-entrancy would be unsafe (inside a paint, inside another listener).

The distinction is not cosmetic: a control whose setter ALWAYS notifies cannot be synced from its own listener without a manual re-entrancy guard at every call site.