97 lines
4.2 KiB
Plaintext
97 lines
4.2 KiB
Plaintext
@namespace DeepDrftPublic.Client.Controls
|
|
@using DeepDrftPublic.Client.Services
|
|
@inject MixVisualizerControlState ControlState
|
|
|
|
@* The Mix visualizer controls (Phase 10, Wave 4). Four continuous RadialKnobs — resolution,
|
|
bubblyness, detach, color-shift speed — laid out in a row. This component lives inside the
|
|
lava-lamp popover on the Mix detail page (Wave 4 moved it out of the always-visible TopContent row).
|
|
It owns NO JS interop: it mutates the shared, session-scoped MixVisualizerControlState and raises its
|
|
Changed event. The backdrop bridge (MixWaveformVisualizer) subscribes to that event and pushes the
|
|
affected uniform to the WebGL module. That keeps the JS module handle single-owned by the bridge and
|
|
this component purely presentational. None of these is a seek surface (spec §D).
|
|
|
|
RadialKnob has no icon slot (its Label renders as SVG text), so each control's Material icon rides
|
|
beside its knob as an adjacent MudIcon caption (spec §7e). HoldValue stays false so the knobs are
|
|
live — ValueChanged fires continuously during drag, exactly as the sliders fired before, preserving
|
|
the "visibly and continuously affects its target" feel and the Changed/NotifyChanged seam. *@
|
|
|
|
<div class="mix-visualizer-controls">
|
|
|
|
@* RadialKnob exposes no aria-label/attribute-capture and is out of scope to modify, so the
|
|
accessible name rides on the wrapping group div instead (a plain element accepts it). *@
|
|
<div class="mix-visualizer-control" role="group" aria-label="Resolution (visible time-span)">
|
|
<RadialKnob Value="@ResolutionFraction"
|
|
ValueChanged="@OnResolutionChanged"
|
|
Min="0"
|
|
Max="1"
|
|
Step="0.001"
|
|
Size="72"
|
|
Color="Color.Primary" />
|
|
<MudIcon Icon="@Icons.Material.Filled.ZoomIn" Size="Size.Small" Class="mix-visualizer-control-icon" />
|
|
</div>
|
|
|
|
<div class="mix-visualizer-control" role="group" aria-label="Bubblyness">
|
|
<RadialKnob Value="@ControlState.Bubblyness"
|
|
ValueChanged="@OnBubblynessChanged"
|
|
Min="0"
|
|
Max="1"
|
|
Step="0.001"
|
|
Size="72"
|
|
Color="Color.Primary" />
|
|
<MudIcon Icon="@Icons.Material.Filled.BubbleChart" Size="Size.Small" Class="mix-visualizer-control-icon" />
|
|
</div>
|
|
|
|
<div class="mix-visualizer-control" role="group" aria-label="Detach (unleash the lava lamp)">
|
|
<RadialKnob Value="@ControlState.Detach"
|
|
ValueChanged="@OnDetachChanged"
|
|
Min="0"
|
|
Max="1"
|
|
Step="0.001"
|
|
Size="72"
|
|
Color="Color.Primary" />
|
|
<MudIcon Icon="@Icons.Material.Filled.Air" Size="Size.Small" Class="mix-visualizer-control-icon" />
|
|
</div>
|
|
|
|
<div class="mix-visualizer-control" role="group" aria-label="Color-shift speed">
|
|
<RadialKnob Value="@ControlState.ColorShiftSpeed"
|
|
ValueChanged="@OnColorShiftSpeedChanged"
|
|
Min="0"
|
|
Max="1"
|
|
Step="0.001"
|
|
Size="72"
|
|
Color="Color.Primary" />
|
|
<MudIcon Icon="@Icons.Material.Filled.Palette" Size="Size.Small" Class="mix-visualizer-control-icon" />
|
|
</div>
|
|
|
|
</div>
|
|
|
|
@code {
|
|
// Resolution rides the log mapping (knob fraction [0,1] ↔ visible seconds); the other three are
|
|
// already normalized [0,1] and bind to their state properties directly.
|
|
private double ResolutionFraction => MixZoomMapping.SecondsToFraction(ControlState.VisibleSeconds);
|
|
|
|
private void OnResolutionChanged(double fraction)
|
|
{
|
|
ControlState.VisibleSeconds = MixZoomMapping.FractionToSeconds(fraction);
|
|
ControlState.NotifyChanged();
|
|
}
|
|
|
|
private void OnBubblynessChanged(double value)
|
|
{
|
|
ControlState.Bubblyness = value;
|
|
ControlState.NotifyChanged();
|
|
}
|
|
|
|
private void OnDetachChanged(double value)
|
|
{
|
|
ControlState.Detach = value;
|
|
ControlState.NotifyChanged();
|
|
}
|
|
|
|
private void OnColorShiftSpeedChanged(double value)
|
|
{
|
|
ControlState.ColorShiftSpeed = value;
|
|
ControlState.NotifyChanged();
|
|
}
|
|
}
|