Files
Terminal.Gui/Examples/UICatalog/Scenarios/Mouse.cs
BDisp 00aaefb962 Fixes #3951. Adds View dependency to DimFunc and PosFunc (#4210)
* Fixes #4208. MainLoopSyncContext doesn't work with the v2 drivers

* Fixes #3951. Add DimFuncWithView with a View dependency

* Revert to iteration which will handle the necessary processes

* Revert "Revert to iteration which will handle the necessary processes"

This reverts commit 50015ac6da.

* Layout and draw before position cursor

* Add optional View parameter and property to the DimFunc and PosFunc

* Trying fix unit test error

* Revert layout changes

* Fixes #4216. Legacy drivers aren't refreshing the screen correctly on view drag

* Add assertion proving NeedsLayout is always false before call OnSubViewsLaidOut

* Fix unit test error

* Increasing time to abort

* Revert "Increasing time to abort"

This reverts commit d7306e72f3.

* Trying fix integration tests

* Still trying fix integrations unit tests

* Revert comment

* Layout is performed during the iteration

* Using Dim.Func with status bar view

* Still trying fix integrations tests by locking _subviews

* Still trying fix integrations tests by locking _subviews

* Add internal SnapshotSubviews method

* Remove lock from SnapshotSubviews method

* Using SnapshotSubviews method in the DrawSubViews method

* Remove lock from SnapshotSubviews method

* Using SnapshotSubviews method in the DrawSubViews method

* Using SnapshotSubviews

* Prevent new app if the previous wasn't yet finished

* Replace SnapshotSubviews method with ViewCollectionHelpers class

* Lock entire GuiTestContext constructor

* Using Snapshot in the ordered field

* Fixes #4221 Extra modifiers f1 to f4 in v2net (#4220)

* Assume we are running in a terminal that supports true color by default unless user explicitly forces 16

* Add support for extra modifiers for F1 to F4 keys

* Revert "Assume we are running in a terminal that supports true color by default unless user explicitly forces 16"

This reverts commit 4cc2530de0.

* Cleanup

* Update comments

* Code cleanup

---------

Co-authored-by: Tig <tig@users.noreply.github.com>

* Move ViewCollectionHelpers class to a separate file

* Remove Border.Layout call in the DoDrawAdornmentsSubViews method.

* Remove adornments layout call within the draw

---------

Co-authored-by: Tig <tig@users.noreply.github.com>
Co-authored-by: Thomas Nind <31306100+tznind@users.noreply.github.com>
2025-09-01 10:40:10 -06:00

376 lines
16 KiB
C#

using System.Collections.ObjectModel;
namespace UICatalog.Scenarios;
[ScenarioMetadata ("Mouse", "Demonstrates Mouse Events and States")]
[ScenarioCategory ("Mouse and Keyboard")]
public class Mouse : Scenario
{
public override void Main ()
{
Application.Init ();
Window win = new ()
{
Id = "win",
Title = GetQuitKeyAndName ()
};
Slider<MouseFlags> filterSlider = new ()
{
Title = "_Filter",
X = 0,
Y = 0,
BorderStyle = LineStyle.Single,
Type = SliderType.Multiple,
Orientation = Orientation.Vertical,
UseMinimumSize = true,
MinimumInnerSpacing = 0
};
filterSlider.Options = Enum.GetValues (typeof (MouseFlags))
.Cast<MouseFlags> ()
.Where (value => !value.ToString ().Contains ("None") && !value.ToString ().Contains ("All"))
.Select (
value => new SliderOption<MouseFlags>
{
Legend = value.ToString (),
Data = value
})
.ToList ();
for (var i = 0; i < filterSlider.Options.Count; i++)
{
if (filterSlider.Options [i].Data != MouseFlags.ReportMousePosition)
{
filterSlider.SetOption (i);
}
}
win.Add (filterSlider);
var clearButton = new Button
{
Title = "_Clear Logs",
X = 1,
Y = Pos.Bottom (filterSlider) + 1
};
win.Add (clearButton);
Label ml;
var count = 0;
ml = new () { X = Pos.Right (filterSlider), Y = 0, Text = "Mouse: " };
win.Add (ml);
CheckBox cbWantContinuousPresses = new ()
{
X = Pos.Right (filterSlider),
Y = Pos.Bottom (ml),
Title = "_Want Continuous Button Pressed"
};
win.Add (cbWantContinuousPresses);
CheckBox cbHighlightOnPressed = new ()
{
X = Pos.Right (filterSlider),
Y = Pos.Bottom (cbWantContinuousPresses),
Title = "_Highlight on Pressed"
};
win.Add (cbHighlightOnPressed);
CheckBox cbHighlightOnPressedOutside = new ()
{
X = Pos.Right (filterSlider),
Y = Pos.Bottom (cbHighlightOnPressed),
Title = "_Highlight on PressedOutside"
};
win.Add (cbHighlightOnPressedOutside);
var demo = new MouseEventDemoView
{
Id = "demo",
X = Pos.Right (filterSlider),
Y = Pos.Bottom (cbHighlightOnPressedOutside),
Width = Dim.Fill (),
Height = 15,
Title = "Enter/Leave Demo"
};
demo.Padding!.Initialized += DemoPaddingOnInitialized;
void DemoPaddingOnInitialized (object o, EventArgs eventArgs)
{
demo.Padding!.Add (
new MouseEventDemoView
{
X = 0,
Y = 0,
Width = Dim.Fill (),
Height = Dim.Func (_ => demo.Padding.Thickness.Top),
Title = "inPadding",
Id = "inPadding"
});
demo.Padding.Thickness = demo.Padding.Thickness with { Top = 5 };
}
View sub1 = new MouseEventDemoView
{
X = 0,
Y = 0,
Width = Dim.Percent (20),
Height = Dim.Fill (),
Title = "sub1",
Id = "sub1"
};
demo.Add (sub1);
View sub2 = new MouseEventDemoView
{
X = Pos.Right (sub1) - 4,
Y = Pos.Top (sub1) + 1,
Width = Dim.Percent (20),
Height = Dim.Fill (1),
Title = "sub2",
Id = "sub2"
};
demo.Add (sub2);
win.Add (demo);
cbHighlightOnPressed.CheckedState = demo.HighlightStates.HasFlag (MouseState.Pressed) ? CheckState.Checked : CheckState.UnChecked;
cbHighlightOnPressed.CheckedStateChanging += (s, e) =>
{
if (e.Result == CheckState.Checked)
{
demo.HighlightStates |= MouseState.Pressed;
}
else
{
demo.HighlightStates &= ~MouseState.Pressed;
}
foreach (View subview in demo.SubViews)
{
if (e.Result == CheckState.Checked)
{
subview.HighlightStates |= MouseState.Pressed;
}
else
{
subview.HighlightStates &= ~MouseState.Pressed;
}
}
foreach (View subview in demo.Padding.SubViews)
{
if (e.Result == CheckState.Checked)
{
subview.HighlightStates |= MouseState.Pressed;
}
else
{
subview.HighlightStates &= ~MouseState.Pressed;
}
}
};
cbHighlightOnPressedOutside.CheckedState = demo.HighlightStates.HasFlag (MouseState.PressedOutside) ? CheckState.Checked : CheckState.UnChecked;
cbHighlightOnPressedOutside.CheckedStateChanging += (s, e) =>
{
if (e.Result == CheckState.Checked)
{
demo.HighlightStates |= MouseState.PressedOutside;
}
else
{
demo.HighlightStates &= ~MouseState.PressedOutside;
}
foreach (View subview in demo.SubViews)
{
if (e.Result == CheckState.Checked)
{
subview.HighlightStates |= MouseState.PressedOutside;
}
else
{
subview.HighlightStates &= ~MouseState.PressedOutside;
}
}
foreach (View subview in demo.Padding.SubViews)
{
if (e.Result == CheckState.Checked)
{
subview.HighlightStates |= MouseState.PressedOutside;
}
else
{
subview.HighlightStates &= ~MouseState.PressedOutside;
}
}
};
cbWantContinuousPresses.CheckedStateChanging += (s, e) =>
{
demo.WantContinuousButtonPressed = !demo.WantContinuousButtonPressed;
foreach (View subview in demo.SubViews)
{
subview.WantContinuousButtonPressed = demo.WantContinuousButtonPressed;
}
foreach (View subview in demo.Padding.SubViews)
{
subview.WantContinuousButtonPressed = demo.WantContinuousButtonPressed;
}
};
var label = new Label
{
Text = "_App Events:",
X = Pos.Right (filterSlider),
Y = Pos.Bottom (demo)
};
ObservableCollection<string> appLogList = new ();
var appLog = new ListView
{
X = Pos.Left (label),
Y = Pos.Bottom (label),
Width = 50,
Height = Dim.Fill (),
SchemeName = "TopLevel",
Source = new ListWrapper<string> (appLogList)
};
win.Add (label, appLog);
Application.MouseEvent += (sender, a) =>
{
int i = filterSlider.Options.FindIndex (o => o.Data == a.Flags);
if (filterSlider.GetSetOptions ().Contains (i))
{
ml.Text = $"MouseEvent: ({a.Position}) - {a.Flags} {count}";
appLogList.Add ($"({a.Position}) - {a.Flags} {count++}");
appLog.MoveDown ();
}
};
label = new ()
{
Text = "_Window Events:",
X = Pos.Right (appLog) + 1,
Y = Pos.Top (label)
};
ObservableCollection<string> winLogList = new ();
var winLog = new ListView
{
X = Pos.Left (label),
Y = Pos.Bottom (label),
Width = Dim.Percent (50),
Height = Dim.Fill (),
SchemeName = "TopLevel",
Source = new ListWrapper<string> (winLogList)
};
win.Add (label, winLog);
clearButton.Accepting += (s, e) =>
{
appLogList.Clear ();
appLog.SetSource (appLogList);
winLogList.Clear ();
winLog.SetSource (winLogList);
};
win.MouseEvent += (sender, a) =>
{
int i = filterSlider.Options.FindIndex (o => o.Data == a.Flags);
if (filterSlider.GetSetOptions ().Contains (i))
{
winLogList.Add ($"MouseEvent: ({a.Position}) - {a.Flags} {count++}");
winLog.MoveDown ();
}
};
win.MouseClick += (sender, a) =>
{
winLogList.Add ($"MouseClick: ({a.Position}) - {a.Flags} {count++}");
winLog.MoveDown ();
};
Application.Run (win);
win.Dispose ();
Application.Shutdown ();
}
public class MouseEventDemoView : View
{
public MouseEventDemoView ()
{
CanFocus = true;
Id = "mouseEventDemoView";
Initialized += OnInitialized;
MouseLeave += (s, e) => { Text = "Leave"; };
MouseEnter += (s, e) => { Text = "Enter"; };
return;
void OnInitialized (object sender, EventArgs e)
{
TextAlignment = Alignment.Center;
VerticalTextAlignment = Alignment.Center;
Padding!.Thickness = new (1, 1, 1, 1);
Padding!.SetScheme (new (new Attribute (Color.Black)));
Padding.Id = $"{Id}.Padding";
Border!.Thickness = new (1);
Border.LineStyle = LineStyle.Rounded;
Border.Id = $"{Id}.Border";
MouseStateChanged += (_, args) =>
{
if (args.Value.HasFlag (MouseState.PressedOutside))
{
Border.LineStyle = LineStyle.Dotted;
}
else
{
Border.LineStyle = LineStyle.Single;
}
SetNeedsDraw ();
};
}
}
/// <inheritdoc/>
protected override bool OnGettingAttributeForRole (in VisualRole role, ref Attribute currentAttribute)
{
if (role == VisualRole.Normal)
{
if (MouseState.HasFlag (MouseState.Pressed) && HighlightStates.HasFlag (MouseState.Pressed))
{
currentAttribute = currentAttribute with { Background = currentAttribute.Foreground.GetBrighterColor () };
return true;
}
}
return base.OnGettingAttributeForRole (in role, ref currentAttribute);
}
}
}