Player Tool Bar
Layout
Player Tool Bar
Status Text Field
Start Button
Pause Button
Run-One-Line Button
Run-One-Step Button
Stop Button
Reset Button
Behavior of Player Tool Bar
See the example code to:
- complete the behavior of the buttons and
Status Text Field
. - The rapidly used buttons should has hotkey. At least the following buttons:
- Run One Line Button
- Run One Step Button
- Start/Continue
- Pause
- Add and remove the event to the PacePlayer on
Player Tool Bar
initialization and finalization. The events update theStatus Text Field
. - Alter the background color of the
Status Text Field
if the status changed.- Warning style color
- Running
- Secondary style color
- Paused
- No Project
- Success style color
- Finished
- Ready
- Warning style color
The action of Reset Button
should be async for user experience.
Tip
Use icon instead of text to the tool bar button. Run One Line Button and Run One Step Button use the same icon, use the different color to resolve them.
- Run One Line Button > default color with green seasoned
- Run One Step Button > default color with blue seasoned
The other button use the default color is enough.
Example Code
@using Hi.Common.PathUtils;
@using Hi.HiNcKits;
@using Hi.MachiningProcs
@using Hi.MillingProcs;
@using Hi.Numerical.FilePlayers;
@inject HiNcHost hiNcHost
@{
MachiningProject machiningProject = hiNcHost.MachiningProject;
bool disabledByMachiningProject = machiningProject == null;
}
<div class="btn-group" role="group">
<div class=" btn-group"
data-bs-toggle="collapse" data-bs-target="#player-@Tid">
<button class="btn btn-outline-info text-nowrap "
disabled="@disabledByMachiningProject"
data-bs-toggle="button">
<span class="me-1">@Loc["Player"]</span>
<div class="d-inline-block" style="width: 4rem">
@{
if (machiningProject == null) { }
else if (machiningProject.PacePlayer.IsRunning)
{
<span class="badge text-bg-warning">@Loc["Running"]</span>
}
else if (machiningProject.PacePlayer.IsLocked)
{
<span class="badge text-bg-secondary">@Loc["Pause"]</span>
}
else if (machiningProject.PacePlayer.IsFinished)
{
<span class="badge text-bg-success">@Loc["Finish"]</span>
}
else
{
<span class="badge text-bg-primary">@Loc["Unlocked"]</span>
}
}
</div>
</button>
</div>
<div id="player-@Tid" class="btn-group collapse collapse-horizontal show" role="group">
@if (machiningProject == null) { }
else if (!machiningProject.PacePlayer.IsLocked)
{
<button class="btn btn-primary text-nowrap" title="@Loc["Start"] (S)"
accesskey="s"
disabled="@(disabledByMachiningProject||machiningProject.PacePlayer.IsFinished)"
@onclick="StartOrContinue">
<span class="oi oi-media-play me-1"></span>
</button>
}
else
{
<button class="btn btn-primary text-nowrap" title="@Loc["Continue"] (S)"
accesskey="s"
@onclick="StartOrContinue"
disabled="@(disabledByMachiningProject||machiningProject.PacePlayer.IsFinished||machiningProject.PacePlayer.IsRunning)">
<span class="oi oi-media-play me-1"></span>
</button>
}
<button class="btn btn-primary text-nowrap" title="@Loc["Pause"] (P)"
accesskey="p"
@onclick="Pause"
disabled="@(disabledByMachiningProject||!machiningProject.PacePlayer.IsRunning)">
<span class="oi oi-media-pause me-1"></span>
</button>
<button class="btn btn-primary text-nowrap" title="@Loc["Run One Line"] (L)"
accesskey="l"
@onclick="RunToLineEnd"
disabled="@(disabledByMachiningProject||machiningProject.PacePlayer.IsFinished)">
<span class="oi oi-media-step-forward me-1"></span>
</button>
<button class="btn btn-primary text-nowrap" title="@Loc["Run One Step"] (K)"
accesskey="k"
@onclick="RunToNextPace"
disabled="@(disabledByMachiningProject||machiningProject.PacePlayer.IsFinished)">
<CommonRcl.Shared.CombinedIcon>
<IconA>
<span class="oi oi-media-step-forward me-1"></span>
</IconA>
<IconB>
<span class="badge rounded-pill bg-primary-subtle text-primary-emphasis">
step
</span>
</IconB>
</CommonRcl.Shared.CombinedIcon>
</button>
<button class="btn btn-primary text-nowrap" title="@Loc["Break"]"
@onclick="@Break"
disabled="@(disabledByMachiningProject||!(machiningProject.PacePlayer.IsLocked||machiningProject.PacePlayer.IsFinished))">
<span class="oi oi-media-stop me-1"></span>
</button>
<button class="btn btn-primary text-nowrap" title="@Loc["Reset"]"
disabled="@disabledByMachiningProject"
@onclick="Reset">
<span class="bi bi-backspace"></span>
</button>
</div>
</div>
using Hi.Common;
using Hi.MachiningProcs;
using Hi.Parallels;
using Microsoft.AspNetCore.Components;
namespace HiNcRcl.Areas.Player
{
public partial class PlayerButtonGroup : IAsyncDisposable
{
[Parameter]
public string Tid { set; get; } = System.Guid.NewGuid().ToString();
StringLocalizer Loc { get; } = new StringLocalizer(typeof(PlayerDiv));
SemaphoreSlim DisposeSemaphore { get; } = new SemaphoreSlim(1);
MachiningProject MachiningProject => hiNcHost.MachiningProject;
bool disposedValue = false;
/// <inheritdoc/>
protected override async Task OnAfterRenderAsync(bool firstRender)
{
base.OnAfterRender(firstRender);
if (firstRender)
{
using var _ = await DisposeSemaphore.EmbraceAsync();
if (disposedValue) return;
var machiningProject = MachiningProject;
if (machiningProject != null)
{
machiningProject.PacePlayer.IsLockedEventHandler
+= EnumerablePlayer_IsLockedEventHandler;
machiningProject.PacePlayer.IsRunningChangedEvent
+= EnumerablePlayer_IsLockedEventHandler;
}
}
}
/// <inheritdoc/>
public async ValueTask DisposeAsync()
{
using var _ = await DisposeSemaphore.EmbraceAsync();
var machiningProject = MachiningProject;
if (machiningProject != null)
{
machiningProject.PacePlayer.IsLockedEventHandler
-= EnumerablePlayer_IsLockedEventHandler;
machiningProject.PacePlayer.IsRunningChangedEvent
-= EnumerablePlayer_IsLockedEventHandler;
}
disposedValue = true;
await ValueTask.CompletedTask;
}
private void EnumerablePlayer_IsLockedEventHandler(bool obj)
{
InvokeAsync(StateHasChanged).ConfigureAwait(false);
}
public void StartOrContinue()
{
if (!MachiningProject.PacePlayer.IsLocked)
{
MachiningProject.PacePlayer.Start();
}
else if (!MachiningProject.PacePlayer.IsRunning
&& !MachiningProject.PacePlayer.IsFinished)
{
MachiningProject.PacePlayer.Resume();
}
}
public void Pause()
{
MachiningProject?.PacePlayer.Pause();
}
public void RunToLineEnd()
{
MachiningProject?.NcRunner.RunToLineEnd();
}
public void RunToNextPace()
{
MachiningProject?.PacePlayer.RunToNextPace();
}
public void Break()
{
MachiningProject?.PacePlayer.Terminate();
}
public async Task Reset()
{
await Task.Run(() => {
MachiningProject?.PacePlayer.Reset();
}).ShowIfCatched(this);
}
}
}
Single-User WPF Application Source Code Path
- Play/PlayerToolBar
see this page for git repository.