Skip to content

Commit 3fe1760

Browse files
DanielPowerFeodor0090peppybdach
authored
Expose tablet OutputSize (ppy#6460)
* Add output area and size to OTD handler * Expose area properties via `ITabletHandler` * Add better explanation how `OutputAreaPosition` works * Remove mention about osu!'s component * Initial proof of concept for tablet output scaling * Remove console log * Fix unintended changes from merging old branch * Undo unintended change * Update wording for OutputAreaPosition summary * Remove trivial comments * Simplify scaling/positioning logic * Address ambiguous arithmetic precedence * Address ambiguous arithmetic precedence * Minor cleanup * Address conflict * Fix test UI for tablet output area * Fix output area position and add testing sliders * Remove unnecessary updateOutputArea call * Restore default values * Add visualizer for output area * Display tablet rotation in visualiser * Adjust some `BindValueChanged()` calls --------- Co-authored-by: Fyodor Ryzhov <[email protected]> Co-authored-by: Dean Herbert <[email protected]> Co-authored-by: Bartłomiej Dach <[email protected]>
1 parent 048bd87 commit 3fe1760

File tree

3 files changed

+99
-20
lines changed

3 files changed

+99
-20
lines changed

osu.Framework.Tests/Visual/Input/TestSceneTabletInput.cs

Lines changed: 73 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ namespace osu.Framework.Tests.Visual.Input
2121
public partial class TestSceneTabletInput : FrameworkTestScene
2222
{
2323
private readonly SpriteText tabletInfo;
24-
private readonly TabletAreaVisualiser areaVisualizer;
24+
private readonly TabletAreaVisualiser inputAreaVisualizer;
25+
private readonly TabletAreaVisualiser outputAreaVisualizer;
2526
private readonly FillFlowContainer penButtonFlow;
2627
private readonly FillFlowContainer auxButtonFlow;
2728
private IBindable<TabletInfo?> tablet = new Bindable<TabletInfo?>();
@@ -40,7 +41,8 @@ public TestSceneTabletInput()
4041
Children = new Drawable[]
4142
{
4243
tabletInfo = new SpriteText(),
43-
areaVisualizer = new TabletAreaVisualiser(),
44+
inputAreaVisualizer = new TabletAreaVisualiser(Vector2.One, "Input area", false),
45+
outputAreaVisualizer = new TabletAreaVisualiser(new Vector2(256, 144), "Output area", true),
4446
penButtonFlow = new FillFlowContainer
4547
{
4648
RelativeSizeAxes = Axes.X,
@@ -73,8 +75,11 @@ protected override void LoadComplete()
7375

7476
if (tabletHandler != null)
7577
{
76-
areaVisualizer.AreaSize.BindTo(tabletHandler.AreaSize);
77-
areaVisualizer.AreaOffset.BindTo(tabletHandler.AreaOffset);
78+
inputAreaVisualizer.AreaSize.BindTo(tabletHandler.AreaSize);
79+
inputAreaVisualizer.AreaOffset.BindTo(tabletHandler.AreaOffset);
80+
inputAreaVisualizer.AreaRotation.BindTo(tabletHandler.Rotation);
81+
outputAreaVisualizer.AreaSize.BindTo(tabletHandler.OutputAreaSize);
82+
outputAreaVisualizer.AreaOffset.BindTo(tabletHandler.OutputAreaOffset);
7883

7984
tablet = tabletHandler.Tablet.GetBoundCopy();
8085
tablet.BindValueChanged(_ => updateState(), true);
@@ -84,12 +89,12 @@ protected override void LoadComplete()
8489

8590
AddToggleStep("toggle tablet handling", t => tabletHandler.Enabled.Value = t);
8691

87-
AddSliderStep("change width", 0, 1, 1f,
92+
AddSliderStep("change input width", 0, 1, 1f,
8893
width => tabletHandler.AreaSize.Value = new Vector2(
8994
tabletHandler.AreaSize.Default.X * width,
9095
tabletHandler.AreaSize.Value.Y));
9196

92-
AddSliderStep("change height", 0, 1, 1f,
97+
AddSliderStep("change input height", 0, 1, 1f,
9398
height => tabletHandler.AreaSize.Value = new Vector2(
9499
tabletHandler.AreaSize.Value.X,
95100
tabletHandler.AreaSize.Default.Y * height));
@@ -104,6 +109,25 @@ protected override void LoadComplete()
104109
tabletHandler.AreaOffset.Value.X,
105110
tabletHandler.AreaSize.Default.Y * yOffset));
106111

112+
AddSliderStep("change output width", 0, 1, 1f,
113+
width => tabletHandler.OutputAreaSize.Value = new Vector2(
114+
width, tabletHandler.OutputAreaSize.Value.Y));
115+
116+
AddSliderStep("change output height", 0, 1, 1f,
117+
height => tabletHandler.OutputAreaSize.Value = new Vector2(
118+
tabletHandler.OutputAreaSize.Value.X, height));
119+
120+
AddSliderStep("change output X offset", 0, 1, 0.5f,
121+
x => tabletHandler.OutputAreaOffset.Value = new Vector2(
122+
x, tabletHandler.OutputAreaOffset.Value.Y));
123+
124+
AddSliderStep("change output Y offset", 0, 1, 0.5f,
125+
y => tabletHandler.OutputAreaOffset.Value = new Vector2(
126+
tabletHandler.OutputAreaOffset.Value.X, y));
127+
128+
AddSliderStep("change rotation", 0, 360, 0f,
129+
rotation => tabletHandler.Rotation.Value = rotation);
130+
107131
AddSliderStep("change pen pressure threshold for click", 0, 1, 0f,
108132
threshold => tabletHandler.PressureThreshold.Value = threshold);
109133
}
@@ -119,16 +143,31 @@ private void updateState()
119143
else
120144
tabletInfo.Text = "Tablet input is disabled.";
121145

122-
areaVisualizer.Alpha = penButtonFlow.Alpha = auxButtonFlow.Alpha = thresholdTester.Alpha = tablet.Value != null && tabletEnabled.Value ? 1 : 0;
146+
float areaVisualizerAlpha = penButtonFlow.Alpha = auxButtonFlow.Alpha = thresholdTester.Alpha = tablet.Value != null && tabletEnabled.Value ? 1 : 0;
147+
inputAreaVisualizer.Alpha = areaVisualizerAlpha;
148+
outputAreaVisualizer.Alpha = areaVisualizerAlpha;
123149
}
124150

125151
private partial class TabletAreaVisualiser : CompositeDrawable
126152
{
153+
public TabletAreaVisualiser(Vector2 areaScale, string label, bool confineArea)
154+
{
155+
this.areaScale = areaScale;
156+
this.label = label;
157+
this.confineArea = confineArea;
158+
}
159+
160+
private readonly Vector2 areaScale;
161+
private readonly string label;
162+
private readonly bool confineArea;
163+
127164
public readonly Bindable<Vector2> AreaSize = new Bindable<Vector2>();
128165
public readonly Bindable<Vector2> AreaOffset = new Bindable<Vector2>();
166+
public readonly Bindable<float> AreaRotation = new Bindable<float>();
129167

130168
private Box fullArea = null!;
131169
private Container activeArea = null!;
170+
private Box activeAreaBox = null!;
132171

133172
private SpriteText areaText = null!;
134173

@@ -153,10 +192,12 @@ private void load()
153192
Origin = Anchor.Centre,
154193
Children = new Drawable[]
155194
{
156-
new Box
195+
activeAreaBox = new Box
157196
{
158197
RelativeSizeAxes = Axes.Both,
159-
Colour = FrameworkColour.YellowGreen
198+
Anchor = Anchor.Centre,
199+
Origin = Anchor.Centre,
200+
Colour = FrameworkColour.YellowGreen,
160201
},
161202
areaText = new SpriteText
162203
{
@@ -173,15 +214,32 @@ protected override void LoadComplete()
173214
{
174215
base.LoadComplete();
175216

176-
AreaSize.BindValueChanged(size =>
217+
AreaSize.DefaultChanged += _ => updateVisualiser();
218+
AreaSize.BindValueChanged(_ => updateVisualiser());
219+
AreaOffset.BindValueChanged(_ => updateVisualiser());
220+
AreaRotation.BindValueChanged(_ =>
177221
{
178-
activeArea.Size = size.NewValue;
179-
areaText.Text = $"Active area: {size.NewValue}";
222+
activeAreaBox.Rotation = AreaRotation.Value;
180223
}, true);
181-
AreaSize.DefaultChanged += fullSize => fullArea.Size = fullSize.NewValue;
182-
fullArea.Size = AreaSize.Default;
224+
updateVisualiser();
225+
}
226+
227+
private void updateVisualiser()
228+
{
229+
activeArea.Size = AreaSize.Value * areaScale;
230+
areaText.Text = $"{label}: {activeArea.Size}";
231+
fullArea.Size = AreaSize.Default * areaScale;
183232

184-
AreaOffset.BindValueChanged(offset => activeArea.Position = offset.NewValue, true);
233+
// Handles the difference in positioning behavior between Input Area and Output Area
234+
if (confineArea)
235+
{
236+
Vector2 offsetFromCenter = (AreaOffset.Value - new Vector2(0.5f, 0.5f)) * (AreaSize.Default - AreaSize.Value) * areaScale;
237+
activeArea.Position = (fullArea.Size / 2) + offsetFromCenter;
238+
}
239+
else
240+
{
241+
activeArea.Position = AreaOffset.Value;
242+
}
185243
}
186244
}
187245

osu.Framework/Input/Handlers/Tablet/ITabletHandler.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,18 @@ public interface ITabletHandler
2222
/// </summary>
2323
Bindable<Vector2> AreaSize { get; }
2424

25+
/// <summary>
26+
/// The relative position of the output area in the game window.
27+
/// Values range from (0,0) for top-left to (1,1) for bottom-right.
28+
/// Has no effect when <see cref="OutputAreaSize"/> is (1,1).
29+
/// </summary>
30+
Bindable<Vector2> OutputAreaOffset { get; }
31+
32+
/// <summary>
33+
/// Relative size of output area inside game window.
34+
/// </summary>
35+
Bindable<Vector2> OutputAreaSize { get; }
36+
2537
/// <summary>
2638
/// Information on the currently connected tablet device. May be null if no tablet is detected.
2739
/// </summary>

osu.Framework/Input/Handlers/Tablet/OpenTabletDriverHandler.cs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ public class OpenTabletDriverHandler : InputHandler, IAbsolutePointer, IRelative
3838

3939
public Bindable<Vector2> AreaSize { get; } = new Bindable<Vector2>();
4040

41+
public Bindable<Vector2> OutputAreaOffset { get; } = new Bindable<Vector2>(new Vector2(0.5f, 0.5f));
42+
43+
public Bindable<Vector2> OutputAreaSize { get; } = new Bindable<Vector2>(new Vector2(1f, 1f));
44+
4145
public Bindable<float> Rotation { get; } = new Bindable<float>();
4246

4347
public BindableFloat PressureThreshold { get; } = new BindableFloat(0.0f)
@@ -68,6 +72,9 @@ public override bool Initialize(GameHost host)
6872
AreaSize.BindValueChanged(_ => updateTabletAndInputArea(device));
6973
Rotation.BindValueChanged(_ => updateTabletAndInputArea(device), true);
7074

75+
OutputAreaOffset.BindValueChanged(_ => updateOutputArea(host.Window));
76+
OutputAreaSize.BindValueChanged(_ => updateOutputArea(host.Window), true);
77+
7178
Enabled.BindValueChanged(enabled =>
7279
{
7380
if (enabled.NewValue)
@@ -149,14 +156,16 @@ private void updateOutputArea(IWindow window)
149156
{
150157
case AbsoluteOutputMode absoluteOutputMode:
151158
{
152-
float outputWidth, outputHeight;
159+
Vector2 windowSize = new Vector2(window.ClientSize.Width, window.ClientSize.Height);
160+
Vector2 scaledSize = windowSize * OutputAreaSize.Value;
161+
Vector2 offsetFromCenter = (OutputAreaOffset.Value - new Vector2(0.5f, 0.5f)) * (windowSize - scaledSize);
162+
Vector2 position = (windowSize / 2) + offsetFromCenter;
153163

154-
// Set output area in pixels
155164
absoluteOutputMode.Output = new Area
156165
{
157-
Width = outputWidth = window.ClientSize.Width,
158-
Height = outputHeight = window.ClientSize.Height,
159-
Position = new System.Numerics.Vector2(outputWidth / 2, outputHeight / 2)
166+
Width = scaledSize.X,
167+
Height = scaledSize.Y,
168+
Position = position.ToSystemNumerics()
160169
};
161170
break;
162171
}

0 commit comments

Comments
 (0)