mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
Merge remote-tracking branch 'upstream/main' into main
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
<PackageReference Include="Pharmacist.MsBuild" Version="2.0.8" PrivateAssets="all" />
|
||||
<PackageReference Include="Pharmacist.Common" Version="2.0.8" />
|
||||
<PackageReference Include="Terminal.Gui" Version="1.0.0.*" />
|
||||
<PackageReference Include="ReactiveUI.Fody" Version="13.2.18" />
|
||||
<PackageReference Include="ReactiveUI" Version="13.2.18" />
|
||||
<PackageReference Include="ReactiveUI.Fody" Version="13.3.2" />
|
||||
<PackageReference Include="ReactiveUI" Version="13.3.2" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -110,6 +110,15 @@ namespace Terminal.Gui {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Alternative key to navigate forwards through all views. Ctrl+Tab is always used.
|
||||
/// </summary>
|
||||
public static Key AlternateForwardKey { get; set; } = Key.PageDown | Key.CtrlMask;
|
||||
/// <summary>
|
||||
/// Alternative key to navigate backwards through all views. Shift+Ctrl+Tab is always used.
|
||||
/// </summary>
|
||||
public static Key AlternateBackwardKey { get; set; } = Key.PageUp | Key.CtrlMask;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="MainLoop"/> driver for the application
|
||||
/// </summary>
|
||||
|
||||
@@ -242,13 +242,12 @@ namespace Terminal.Gui {
|
||||
/// <returns>The <see cref="Pos"/> that is the sum of the values of <c>left</c> and <c>right</c>.</returns>
|
||||
public static Pos operator + (Pos left, Pos right)
|
||||
{
|
||||
PosCombine newPos = new PosCombine (true, left, right);
|
||||
if (posCombine?.ToString () != newPos.ToString ()) {
|
||||
var view = left as PosView;
|
||||
if (view != null) {
|
||||
view.Target.SetNeedsLayout ();
|
||||
}
|
||||
if (left is PosAbsolute && right is PosAbsolute) {
|
||||
posCombine = null;
|
||||
return new PosAbsolute (left.Anchor (0) + right.Anchor (0));
|
||||
}
|
||||
PosCombine newPos = new PosCombine (true, left, right);
|
||||
SetPosCombine (left, newPos);
|
||||
return posCombine = newPos;
|
||||
}
|
||||
|
||||
@@ -260,13 +259,23 @@ namespace Terminal.Gui {
|
||||
/// <returns>The <see cref="Pos"/> that is the <c>left</c> minus <c>right</c>.</returns>
|
||||
public static Pos operator - (Pos left, Pos right)
|
||||
{
|
||||
if (left is PosAbsolute && right is PosAbsolute) {
|
||||
posCombine = null;
|
||||
return new PosAbsolute (left.Anchor (0) - right.Anchor (0));
|
||||
}
|
||||
PosCombine newPos = new PosCombine (false, left, right);
|
||||
SetPosCombine (left, newPos);
|
||||
return posCombine = newPos;
|
||||
}
|
||||
|
||||
static void SetPosCombine (Pos left, PosCombine newPos)
|
||||
{
|
||||
if (posCombine?.ToString () != newPos.ToString ()) {
|
||||
var view = left as PosView;
|
||||
if (view != null)
|
||||
if (view != null) {
|
||||
view.Target.SetNeedsLayout ();
|
||||
}
|
||||
}
|
||||
return posCombine = newPos;
|
||||
}
|
||||
|
||||
internal class PosView : Pos {
|
||||
@@ -526,6 +535,8 @@ namespace Terminal.Gui {
|
||||
|
||||
}
|
||||
|
||||
static DimCombine dimCombine;
|
||||
|
||||
/// <summary>
|
||||
/// Adds a <see cref="Terminal.Gui.Dim"/> to a <see cref="Terminal.Gui.Dim"/>, yielding a new <see cref="Dim"/>.
|
||||
/// </summary>
|
||||
@@ -534,7 +545,13 @@ namespace Terminal.Gui {
|
||||
/// <returns>The <see cref="Dim"/> that is the sum of the values of <c>left</c> and <c>right</c>.</returns>
|
||||
public static Dim operator + (Dim left, Dim right)
|
||||
{
|
||||
return new DimCombine (true, left, right);
|
||||
if (left is DimAbsolute && right is DimAbsolute) {
|
||||
dimCombine = null;
|
||||
return new DimAbsolute (left.Anchor (0) + right.Anchor (0));
|
||||
}
|
||||
DimCombine newDim = new DimCombine (true, left, right);
|
||||
SetDimCombine (left, newDim);
|
||||
return dimCombine = newDim;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -545,7 +562,23 @@ namespace Terminal.Gui {
|
||||
/// <returns>The <see cref="Dim"/> that is the <c>left</c> minus <c>right</c>.</returns>
|
||||
public static Dim operator - (Dim left, Dim right)
|
||||
{
|
||||
return new DimCombine (false, left, right);
|
||||
if (left is DimAbsolute && right is DimAbsolute) {
|
||||
dimCombine = null;
|
||||
return new DimAbsolute (left.Anchor (0) - right.Anchor (0));
|
||||
}
|
||||
DimCombine newDim = new DimCombine (false, left, right);
|
||||
SetDimCombine (left, newDim);
|
||||
return dimCombine = newDim;
|
||||
}
|
||||
|
||||
static void SetDimCombine (Dim left, DimCombine newPos)
|
||||
{
|
||||
if (dimCombine?.ToString () != newPos.ToString ()) {
|
||||
var view = left as DimView;
|
||||
if (view != null) {
|
||||
view.Target.SetNeedsLayout ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class DimView : Dim {
|
||||
|
||||
@@ -238,10 +238,18 @@ namespace Terminal.Gui {
|
||||
}
|
||||
return true;
|
||||
case Key.Tab | Key.CtrlMask:
|
||||
case Key key when key == Application.AlternateForwardKey: // Needed on Unix
|
||||
Application.Top.FocusNext ();
|
||||
if (Application.Top.Focused == null) {
|
||||
Application.Top.FocusNext ();
|
||||
}
|
||||
return true;
|
||||
case Key.Tab | Key.ShiftMask | Key.CtrlMask:
|
||||
case Key key when key == Application.AlternateBackwardKey: // Needed on Unix
|
||||
Application.Top.FocusPrev ();
|
||||
if (Application.Top.Focused == null) {
|
||||
Application.Top.FocusPrev ();
|
||||
}
|
||||
return true;
|
||||
case Key.L | Key.CtrlMask:
|
||||
Application.Refresh ();
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.1" PrivateAssets="true" />
|
||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.2" PrivateAssets="true" />
|
||||
<PackageReference Include="NStack.Core" Version="0.16.0" />
|
||||
<PackageReference Include="MinVer" Version="2.5.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
|
||||
@@ -300,10 +300,15 @@ namespace Terminal.Gui {
|
||||
// if the next column is the start of a header
|
||||
else if(columnsToRender.Any(r=>r.X == c+1)){
|
||||
rune = Driver.TopTee;
|
||||
}
|
||||
}
|
||||
else if(c == availableWidth -1){
|
||||
rune = Driver.URCorner;
|
||||
}
|
||||
// if the next console column is the lastcolumns end
|
||||
else if ( Style.ExpandLastColumn == false &&
|
||||
columnsToRender.Any (r => r.IsVeryLast && r.X + r.Width-1 == c)) {
|
||||
rune = Driver.TopTee;
|
||||
}
|
||||
}
|
||||
|
||||
AddRuneAt(Driver,c,row,rune);
|
||||
@@ -324,45 +329,26 @@ namespace Terminal.Gui {
|
||||
for(int i =0 ; i<columnsToRender.Length;i++) {
|
||||
|
||||
var current = columnsToRender[i];
|
||||
var availableWidthForCell = GetCellWidth(columnsToRender,i);
|
||||
|
||||
var colStyle = Style.GetColumnStyleIfAny(current.Column);
|
||||
var colName = current.Column.ColumnName;
|
||||
|
||||
RenderSeparator(current.X-1,row,true);
|
||||
|
||||
|
||||
Move (current.X, row);
|
||||
|
||||
Driver.AddStr(TruncateOrPad(colName,colName,availableWidthForCell ,colStyle));
|
||||
Driver.AddStr(TruncateOrPad(colName,colName,current.Width ,colStyle));
|
||||
|
||||
if (Style.ExpandLastColumn == false && current.IsVeryLast) {
|
||||
RenderSeparator (current.X + current.Width-1, row, true);
|
||||
}
|
||||
}
|
||||
|
||||
//render end of line
|
||||
if(style.ShowVerticalHeaderLines)
|
||||
if (style.ShowVerticalHeaderLines)
|
||||
AddRune(Bounds.Width-1,row,Driver.VLine);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates how much space is available to render index <paramref name="i"/> of the <paramref name="columnsToRender"/> given the remaining horizontal space
|
||||
/// </summary>
|
||||
/// <param name="columnsToRender"></param>
|
||||
/// <param name="i"></param>
|
||||
private int GetCellWidth (ColumnToRender [] columnsToRender, int i)
|
||||
{
|
||||
var current = columnsToRender[i];
|
||||
var next = i+1 < columnsToRender.Length ? columnsToRender[i+1] : null;
|
||||
|
||||
if(next == null) {
|
||||
// cell can fill to end of the line
|
||||
return Bounds.Width - current.X;
|
||||
}
|
||||
else {
|
||||
// cell can fill up to next cell start
|
||||
return next.X - current.X;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void RenderHeaderUnderline(int row,int availableWidth, ColumnToRender[] columnsToRender)
|
||||
{
|
||||
// Renders a line below the table headers (when visible) like:
|
||||
@@ -385,6 +371,11 @@ namespace Terminal.Gui {
|
||||
else if(c == availableWidth -1){
|
||||
rune = Style.ShowVerticalCellLines ? Driver.RightTee : Driver.LRCorner;
|
||||
}
|
||||
// if the next console column is the lastcolumns end
|
||||
else if (Style.ExpandLastColumn == false &&
|
||||
columnsToRender.Any (r => r.IsVeryLast && r.X + r.Width-1 == c)) {
|
||||
rune = Style.ShowVerticalCellLines ? '┼' : Driver.BottomTee;
|
||||
}
|
||||
}
|
||||
|
||||
AddRuneAt(Driver,c,row,rune);
|
||||
@@ -397,11 +388,15 @@ namespace Terminal.Gui {
|
||||
if(style.ShowVerticalCellLines)
|
||||
AddRune(0,row,Driver.VLine);
|
||||
|
||||
//start by clearing the entire line
|
||||
Move (0,row);
|
||||
Driver.SetAttribute (FullRowSelect && IsSelected(0,rowToRender) ? ColorScheme.HotFocus : ColorScheme.Normal);
|
||||
Driver.AddStr (new string(' ',Bounds.Width));
|
||||
|
||||
// Render cells for each visible header for the current row
|
||||
for(int i=0;i< columnsToRender.Length ;i++) {
|
||||
|
||||
var current = columnsToRender[i];
|
||||
var availableWidthForCell = GetCellWidth(columnsToRender,i);
|
||||
|
||||
var colStyle = Style.GetColumnStyleIfAny(current.Column);
|
||||
|
||||
@@ -418,13 +413,17 @@ namespace Terminal.Gui {
|
||||
// Render the (possibly truncated) cell value
|
||||
var representation = GetRepresentation(val,colStyle);
|
||||
|
||||
Driver.AddStr (TruncateOrPad(val,representation,availableWidthForCell,colStyle));
|
||||
Driver.AddStr (TruncateOrPad(val,representation, current.Width, colStyle));
|
||||
|
||||
// If not in full row select mode always, reset color scheme to normal and render the vertical line (or space) at the end of the cell
|
||||
if(!FullRowSelect)
|
||||
Driver.SetAttribute (ColorScheme.Normal);
|
||||
|
||||
RenderSeparator(current.X-1,row,false);
|
||||
|
||||
if (Style.ExpandLastColumn == false && current.IsVeryLast) {
|
||||
RenderSeparator (current.X + current.Width-1, row, false);
|
||||
}
|
||||
}
|
||||
|
||||
//render end of line
|
||||
@@ -1019,21 +1018,26 @@ namespace Terminal.Gui {
|
||||
rowsToRender -= GetHeaderHeight();
|
||||
|
||||
bool first = true;
|
||||
var lastColumn = Table.Columns.Cast<DataColumn> ().Last ();
|
||||
|
||||
foreach (var col in Table.Columns.Cast<DataColumn>().Skip (ColumnOffset)) {
|
||||
|
||||
int startingIdxForCurrentHeader = usedSpace;
|
||||
var colStyle = Style.GetColumnStyleIfAny(col);
|
||||
int colWidth;
|
||||
|
||||
// is there enough space for this column (and it's data)?
|
||||
usedSpace += CalculateMaxCellWidth (col, rowsToRender,colStyle) + padding;
|
||||
usedSpace += colWidth = CalculateMaxCellWidth (col, rowsToRender,colStyle) + padding;
|
||||
|
||||
// no (don't render it) unless its the only column we are render (that must be one massively wide column!)
|
||||
if (!first && usedSpace > availableHorizontalSpace)
|
||||
yield break;
|
||||
|
||||
// there is space
|
||||
yield return new ColumnToRender(col, startingIdxForCurrentHeader);
|
||||
yield return new ColumnToRender(col, startingIdxForCurrentHeader,
|
||||
// required for if we end up here because first == true i.e. we have a single massive width (overspilling bounds) column to present
|
||||
Math.Min(availableHorizontalSpace,colWidth),
|
||||
lastColumn == col);
|
||||
first=false;
|
||||
}
|
||||
}
|
||||
@@ -1215,6 +1219,17 @@ namespace Terminal.Gui {
|
||||
/// </summary>
|
||||
public Dictionary<DataColumn, ColumnStyle> ColumnStyles { get; set; } = new Dictionary<DataColumn, ColumnStyle> ();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Determines rendering when the last column in the table is visible but it's
|
||||
/// content or <see cref="ColumnStyle.MaxWidth"/> is less than the remaining
|
||||
/// space in the control. True (the default) will expand the column to fill
|
||||
/// the remaining bounds of the control. False will draw a column ending line
|
||||
/// and leave a blank column that cannot be selected in the remaining space.
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
public bool ExpandLastColumn {get;set;} = true;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the entry from <see cref="ColumnStyles"/> for the given <paramref name="col"/> or null if no custom styling is defined for it
|
||||
/// </summary>
|
||||
@@ -1254,11 +1269,25 @@ namespace Terminal.Gui {
|
||||
/// </summary>
|
||||
public int X { get; set; }
|
||||
|
||||
public ColumnToRender (DataColumn col, int x)
|
||||
/// <summary>
|
||||
/// The width that the column should occupy as calculated by <see cref="CalculateViewport(Rect, int)"/>. Note that this includes
|
||||
/// space for padding i.e. the separator between columns.
|
||||
/// </summary>
|
||||
public int Width { get; }
|
||||
|
||||
/// <summary>
|
||||
/// True if this column is the very last column in the <see cref="Table"/> (not just the last visible column)
|
||||
/// </summary>
|
||||
public bool IsVeryLast { get; }
|
||||
|
||||
public ColumnToRender (DataColumn col, int x, int width, bool isVeryLast)
|
||||
{
|
||||
Column = col;
|
||||
X = x;
|
||||
Width = width;
|
||||
IsVeryLast = isVeryLast;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -2017,7 +2017,7 @@ namespace Terminal.Gui {
|
||||
StopSelecting ();
|
||||
}
|
||||
int nPageDnShift = Frame.Height - 1;
|
||||
if (currentRow > 0 && currentRow < model.Count) {
|
||||
if (currentRow >= 0 && currentRow < model.Count) {
|
||||
if (columnTrack == -1)
|
||||
columnTrack = currentColumn;
|
||||
currentRow = (currentRow + nPageDnShift) > model.Count
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace UICatalog.Scenarios {
|
||||
private MenuItem miHeaderUnderline;
|
||||
private MenuItem miCellLines;
|
||||
private MenuItem miFullRowSelect;
|
||||
private MenuItem miExpandLastColumn;
|
||||
|
||||
public override void Setup ()
|
||||
{
|
||||
@@ -51,6 +52,7 @@ namespace UICatalog.Scenarios {
|
||||
miHeaderUnderline =new MenuItem ("_HeaderUnderLine", "", () => ToggleUnderline()){Checked = tableView.Style.ShowHorizontalHeaderUnderline, CheckType = MenuItemCheckStyle.Checked },
|
||||
miFullRowSelect =new MenuItem ("_FullRowSelect", "", () => ToggleFullRowSelect()){Checked = tableView.FullRowSelect, CheckType = MenuItemCheckStyle.Checked },
|
||||
miCellLines =new MenuItem ("_CellLines", "", () => ToggleCellLines()){Checked = tableView.Style.ShowVerticalCellLines, CheckType = MenuItemCheckStyle.Checked },
|
||||
miExpandLastColumn = new MenuItem ("_ExpandLastColumn", "", () => ToggleExpandLastColumn()){Checked = tableView.Style.ExpandLastColumn, CheckType = MenuItemCheckStyle.Checked },
|
||||
new MenuItem ("_AllLines", "", () => ToggleAllCellLines()),
|
||||
new MenuItem ("_NoLines", "", () => ToggleNoCellLines()),
|
||||
new MenuItem ("_ClearColumnStyles", "", () => ClearColumnStyles()),
|
||||
@@ -181,6 +183,15 @@ namespace UICatalog.Scenarios {
|
||||
tableView.FullRowSelect= miFullRowSelect.Checked;
|
||||
tableView.Update();
|
||||
}
|
||||
|
||||
private void ToggleExpandLastColumn()
|
||||
{
|
||||
miExpandLastColumn.Checked = !miExpandLastColumn.Checked;
|
||||
tableView.Style.ExpandLastColumn = miExpandLastColumn.Checked;
|
||||
|
||||
tableView.Update();
|
||||
|
||||
}
|
||||
private void ToggleCellLines()
|
||||
{
|
||||
miCellLines.Checked = !miCellLines.Checked;
|
||||
|
||||
@@ -4,7 +4,7 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
// Alais Console to MockConsole so we don't accidentally use Console
|
||||
// Alias Console to MockConsole so we don't accidentally use Console
|
||||
using Console = Terminal.Gui.FakeConsole;
|
||||
|
||||
namespace Terminal.Gui.Core {
|
||||
@@ -19,7 +19,7 @@ namespace Terminal.Gui.Core {
|
||||
[Fact]
|
||||
public void Init_Shutdown_Cleans_Up ()
|
||||
{
|
||||
// Verify inital state is per spec
|
||||
// Verify initial state is per spec
|
||||
Pre_Init_State ();
|
||||
|
||||
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
|
||||
@@ -175,7 +175,7 @@ namespace Terminal.Gui.Core {
|
||||
// Setup Mock driver
|
||||
Init ();
|
||||
|
||||
// Setup some fake kepresses (This)
|
||||
// Setup some fake keypresses (This)
|
||||
var input = "Tests";
|
||||
|
||||
// Put a control-q in at the end
|
||||
@@ -268,5 +268,106 @@ namespace Terminal.Gui.Core {
|
||||
Application.Shutdown ();
|
||||
Assert.Null (SynchronizationContext.Current);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AlternateForwardKey_AlternateBackwardKey_Tests ()
|
||||
{
|
||||
Init ();
|
||||
|
||||
var top = Application.Top;
|
||||
var w1 = new Window ();
|
||||
var v1 = new TextField ();
|
||||
var v2 = new TextView ();
|
||||
w1.Add (v1, v2);
|
||||
|
||||
var w2 = new Window ();
|
||||
var v3 = new CheckBox ();
|
||||
var v4 = new Button ();
|
||||
w2.Add (v3, v4);
|
||||
|
||||
top.Add (w1, w2);
|
||||
|
||||
Application.Iteration += () => {
|
||||
Assert.True (v1.HasFocus);
|
||||
// Using default keys.
|
||||
top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab,
|
||||
new KeyModifiers () { Ctrl = true }));
|
||||
Assert.True (v2.HasFocus);
|
||||
top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab,
|
||||
new KeyModifiers () { Ctrl = true }));
|
||||
Assert.True (v3.HasFocus);
|
||||
top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab,
|
||||
new KeyModifiers () { Ctrl = true }));
|
||||
Assert.True (v4.HasFocus);
|
||||
top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab,
|
||||
new KeyModifiers () { Ctrl = true }));
|
||||
Assert.True (v1.HasFocus);
|
||||
|
||||
top.ProcessKey (new KeyEvent (Key.ShiftMask | Key.CtrlMask | Key.Tab,
|
||||
new KeyModifiers () { Shift = true, Ctrl = true }));
|
||||
Assert.True (v4.HasFocus);
|
||||
top.ProcessKey (new KeyEvent (Key.ShiftMask | Key.CtrlMask | Key.Tab,
|
||||
new KeyModifiers () { Shift = true, Ctrl = true }));
|
||||
Assert.True (v3.HasFocus);
|
||||
top.ProcessKey (new KeyEvent (Key.ShiftMask | Key.CtrlMask | Key.Tab,
|
||||
new KeyModifiers () { Shift = true, Ctrl = true }));
|
||||
Assert.True (v2.HasFocus);
|
||||
top.ProcessKey (new KeyEvent (Key.ShiftMask | Key.CtrlMask | Key.Tab,
|
||||
new KeyModifiers () { Shift = true, Ctrl = true }));
|
||||
Assert.True (v1.HasFocus);
|
||||
|
||||
top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.PageDown,
|
||||
new KeyModifiers () { Ctrl = true }));
|
||||
Assert.True (v2.HasFocus);
|
||||
top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.PageDown,
|
||||
new KeyModifiers () { Ctrl = true }));
|
||||
Assert.True (v3.HasFocus);
|
||||
top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.PageDown,
|
||||
new KeyModifiers () { Ctrl = true }));
|
||||
Assert.True (v4.HasFocus);
|
||||
top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.PageDown,
|
||||
new KeyModifiers () { Ctrl = true }));
|
||||
Assert.True (v1.HasFocus);
|
||||
|
||||
top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.PageUp,
|
||||
new KeyModifiers () { Ctrl = true }));
|
||||
Assert.True (v4.HasFocus);
|
||||
top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.PageUp,
|
||||
new KeyModifiers () { Ctrl = true }));
|
||||
Assert.True (v3.HasFocus);
|
||||
top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.PageUp,
|
||||
new KeyModifiers () { Ctrl = true }));
|
||||
Assert.True (v2.HasFocus);
|
||||
top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.PageUp,
|
||||
new KeyModifiers () { Ctrl = true }));
|
||||
Assert.True (v1.HasFocus);
|
||||
|
||||
// Using another's alternate keys.
|
||||
Application.AlternateForwardKey = Key.F7;
|
||||
Application.AlternateBackwardKey = Key.F6;
|
||||
|
||||
top.ProcessKey (new KeyEvent (Key.F7, new KeyModifiers ()));
|
||||
Assert.True (v2.HasFocus);
|
||||
top.ProcessKey (new KeyEvent (Key.F7, new KeyModifiers ()));
|
||||
Assert.True (v3.HasFocus);
|
||||
top.ProcessKey (new KeyEvent (Key.F7, new KeyModifiers ()));
|
||||
Assert.True (v4.HasFocus);
|
||||
top.ProcessKey (new KeyEvent (Key.F7, new KeyModifiers ()));
|
||||
Assert.True (v1.HasFocus);
|
||||
|
||||
top.ProcessKey (new KeyEvent (Key.F6, new KeyModifiers ()));
|
||||
Assert.True (v4.HasFocus);
|
||||
top.ProcessKey (new KeyEvent (Key.F6, new KeyModifiers ()));
|
||||
Assert.True (v3.HasFocus);
|
||||
top.ProcessKey (new KeyEvent (Key.F6, new KeyModifiers ()));
|
||||
Assert.True (v2.HasFocus);
|
||||
top.ProcessKey (new KeyEvent (Key.F6, new KeyModifiers ()));
|
||||
Assert.True (v1.HasFocus);
|
||||
|
||||
Application.RequestStop ();
|
||||
};
|
||||
|
||||
Application.Run (top);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -590,5 +590,109 @@ namespace Terminal.Gui.Core {
|
||||
Assert.Throws<InvalidOperationException> (() => Application.Run ());
|
||||
Application.Shutdown ();
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void Dim_Add_Operator ()
|
||||
{
|
||||
|
||||
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
|
||||
|
||||
var top = Application.Top;
|
||||
|
||||
var view = new View () { X = 0, Y = 0, Width = 20, Height = 0 };
|
||||
var field = new TextField () { X = 0, Y = Pos.Bottom (view), Width = 20 };
|
||||
var count = 0;
|
||||
|
||||
field.KeyDown += (k) => {
|
||||
if (k.KeyEvent.Key == Key.Enter) {
|
||||
field.Text = $"Label {count}";
|
||||
var label = new Label (field.Text) { X = 0, Y = view.Bounds.Height, Width = 20 };
|
||||
view.Add (label);
|
||||
Assert.Equal ($"Label {count}", label.Text);
|
||||
Assert.Equal ($"Pos.Absolute({count})", label.Y.ToString ());
|
||||
|
||||
Assert.Equal ($"Dim.Absolute({count})", view.Height.ToString ());
|
||||
view.Height += 1;
|
||||
count++;
|
||||
Assert.Equal ($"Dim.Absolute({count})", view.Height.ToString ());
|
||||
}
|
||||
};
|
||||
|
||||
Application.Iteration += () => {
|
||||
while (count < 20) {
|
||||
field.OnKeyDown (new KeyEvent (Key.Enter, new KeyModifiers ()));
|
||||
}
|
||||
|
||||
Application.RequestStop ();
|
||||
};
|
||||
|
||||
var win = new Window ();
|
||||
win.Add (view);
|
||||
win.Add (field);
|
||||
|
||||
top.Add (win);
|
||||
|
||||
Application.Run (top);
|
||||
|
||||
Assert.Equal (20, count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Dim_Subtract_Operator ()
|
||||
{
|
||||
|
||||
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
|
||||
|
||||
var top = Application.Top;
|
||||
|
||||
var view = new View () { X = 0, Y = 0, Width = 20, Height = 0 };
|
||||
var field = new TextField () { X = 0, Y = Pos.Bottom (view), Width = 20 };
|
||||
var count = 20;
|
||||
var listLabels = new List<Label> ();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
field.Text = $"Label {i}";
|
||||
var label = new Label (field.Text) { X = 0, Y = view.Bounds.Height, Width = 20 };
|
||||
view.Add (label);
|
||||
Assert.Equal ($"Label {i}", label.Text);
|
||||
Assert.Equal ($"Pos.Absolute({i})", label.Y.ToString ());
|
||||
listLabels.Add (label);
|
||||
|
||||
Assert.Equal ($"Dim.Absolute({i})", view.Height.ToString ());
|
||||
view.Height += 1;
|
||||
Assert.Equal ($"Dim.Absolute({i + 1})", view.Height.ToString ());
|
||||
}
|
||||
|
||||
field.KeyDown += (k) => {
|
||||
if (k.KeyEvent.Key == Key.Enter) {
|
||||
Assert.Equal ($"Label {count - 1}", listLabels [count - 1].Text);
|
||||
view.Remove (listLabels [count - 1]);
|
||||
|
||||
Assert.Equal ($"Dim.Absolute({count})", view.Height.ToString ());
|
||||
view.Height -= 1;
|
||||
count--;
|
||||
Assert.Equal ($"Dim.Absolute({count})", view.Height.ToString ());
|
||||
}
|
||||
};
|
||||
|
||||
Application.Iteration += () => {
|
||||
while (count > 0) {
|
||||
field.OnKeyDown (new KeyEvent (Key.Enter, new KeyModifiers ()));
|
||||
}
|
||||
|
||||
Application.RequestStop ();
|
||||
};
|
||||
|
||||
var win = new Window ();
|
||||
win.Add (view);
|
||||
win.Add (field);
|
||||
|
||||
top.Add (win);
|
||||
|
||||
Application.Run (top);
|
||||
|
||||
Assert.Equal (0, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -536,5 +536,108 @@ namespace Terminal.Gui.Core {
|
||||
Assert.Throws<InvalidOperationException> (() => Application.Run ());
|
||||
Application.Shutdown ();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Pos_Add_Operator ()
|
||||
{
|
||||
|
||||
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
|
||||
|
||||
var top = Application.Top;
|
||||
|
||||
var view = new View () { X = 0, Y = 0, Width = 20, Height = 20 };
|
||||
var field = new TextField () { X = 0, Y = 0, Width = 20 };
|
||||
var count = 0;
|
||||
|
||||
field.KeyDown += (k) => {
|
||||
if (k.KeyEvent.Key == Key.Enter) {
|
||||
field.Text = $"Label {count}";
|
||||
var label = new Label (field.Text) { X = 0, Y = field.Y, Width = 20 };
|
||||
view.Add (label);
|
||||
Assert.Equal ($"Label {count}", label.Text);
|
||||
Assert.Equal ($"Pos.Absolute({count})", label.Y.ToString ());
|
||||
|
||||
Assert.Equal ($"Pos.Absolute({count})", field.Y.ToString ());
|
||||
field.Y += 1;
|
||||
count++;
|
||||
Assert.Equal ($"Pos.Absolute({count})", field.Y.ToString ());
|
||||
}
|
||||
};
|
||||
|
||||
Application.Iteration += () => {
|
||||
while (count < 20) {
|
||||
field.OnKeyDown (new KeyEvent (Key.Enter, new KeyModifiers ()));
|
||||
}
|
||||
|
||||
Application.RequestStop ();
|
||||
};
|
||||
|
||||
var win = new Window ();
|
||||
win.Add (view);
|
||||
win.Add (field);
|
||||
|
||||
top.Add (win);
|
||||
|
||||
Application.Run (top);
|
||||
|
||||
Assert.Equal (20, count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Pos_Subtract_Operator ()
|
||||
{
|
||||
|
||||
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
|
||||
|
||||
var top = Application.Top;
|
||||
|
||||
var view = new View () { X = 0, Y = 0, Width = 20, Height = 20 };
|
||||
var field = new TextField () { X = 0, Y = 0, Width = 20 };
|
||||
var count = 20;
|
||||
var listLabels = new List<Label> ();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
field.Text = $"Label {i}";
|
||||
var label = new Label (field.Text) { X = 0, Y = field.Y, Width = 20 };
|
||||
view.Add (label);
|
||||
Assert.Equal ($"Label {i}", label.Text);
|
||||
Assert.Equal ($"Pos.Absolute({i})", field.Y.ToString ());
|
||||
listLabels.Add (label);
|
||||
|
||||
Assert.Equal ($"Pos.Absolute({i})", field.Y.ToString ());
|
||||
field.Y += 1;
|
||||
Assert.Equal ($"Pos.Absolute({i + 1})", field.Y.ToString ());
|
||||
}
|
||||
|
||||
field.KeyDown += (k) => {
|
||||
if (k.KeyEvent.Key == Key.Enter) {
|
||||
Assert.Equal ($"Label {count - 1}", listLabels [count - 1].Text);
|
||||
view.Remove (listLabels [count - 1]);
|
||||
|
||||
Assert.Equal ($"Pos.Absolute({count})", field.Y.ToString ());
|
||||
field.Y -= 1;
|
||||
count--;
|
||||
Assert.Equal ($"Pos.Absolute({count})", field.Y.ToString ());
|
||||
}
|
||||
};
|
||||
|
||||
Application.Iteration += () => {
|
||||
while (count > 0) {
|
||||
field.OnKeyDown (new KeyEvent (Key.Enter, new KeyModifiers ()));
|
||||
}
|
||||
|
||||
Application.RequestStop ();
|
||||
};
|
||||
|
||||
var win = new Window ();
|
||||
win.Add (view);
|
||||
win.Add (field);
|
||||
|
||||
top.Add (win);
|
||||
|
||||
Application.Run (top);
|
||||
|
||||
Assert.Equal (0, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,7 +418,92 @@ namespace Terminal.Gui.Views {
|
||||
Assert.Equal(new Point(8,3),selected[5]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
[Fact]
|
||||
public void TableView_ExpandLastColumn_True()
|
||||
{
|
||||
var tv = SetUpMiniTable();
|
||||
|
||||
// the thing we are testing
|
||||
tv.Style.ExpandLastColumn = true;
|
||||
|
||||
tv.Redraw(tv.Bounds);
|
||||
|
||||
string expected = @"
|
||||
┌─┬──────┐
|
||||
│A│B │
|
||||
├─┼──────┤
|
||||
│1│2 │
|
||||
";
|
||||
GraphViewTests.AssertDriverContentsAre(expected);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void TableView_ExpandLastColumn_False()
|
||||
{
|
||||
var tv = SetUpMiniTable();
|
||||
|
||||
// the thing we are testing
|
||||
tv.Style.ExpandLastColumn = false;
|
||||
|
||||
tv.Redraw(tv.Bounds);
|
||||
|
||||
string expected = @"
|
||||
┌─┬─┬────┐
|
||||
│A│B│ │
|
||||
├─┼─┼────┤
|
||||
│1│2│ │
|
||||
";
|
||||
GraphViewTests.AssertDriverContentsAre(expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TableView_ExpandLastColumn_False_ExactBounds()
|
||||
{
|
||||
var tv = SetUpMiniTable();
|
||||
|
||||
// the thing we are testing
|
||||
tv.Style.ExpandLastColumn = false;
|
||||
// width exactly matches the max col widths
|
||||
tv.Bounds = new Rect(0,0,5,4);
|
||||
|
||||
tv.Redraw(tv.Bounds);
|
||||
|
||||
string expected = @"
|
||||
┌─┬─┐
|
||||
│A│B│
|
||||
├─┼─┤
|
||||
│1│2│
|
||||
";
|
||||
GraphViewTests.AssertDriverContentsAre(expected);
|
||||
}
|
||||
|
||||
private TableView SetUpMiniTable ()
|
||||
{
|
||||
|
||||
var tv = new TableView();
|
||||
tv.Bounds = new Rect(0,0,10,4);
|
||||
|
||||
var dt = new DataTable();
|
||||
var colA = dt.Columns.Add("A");
|
||||
var colB = dt.Columns.Add("B");
|
||||
dt.Rows.Add(1,2);
|
||||
|
||||
tv.Table = dt;
|
||||
tv.Style.GetOrCreateColumnStyle(colA).MinWidth=1;
|
||||
tv.Style.GetOrCreateColumnStyle(colA).MinWidth=1;
|
||||
tv.Style.GetOrCreateColumnStyle(colB).MaxWidth=1;
|
||||
tv.Style.GetOrCreateColumnStyle(colB).MaxWidth=1;
|
||||
|
||||
GraphViewTests.InitFakeDriver();
|
||||
tv.ColorScheme = new ColorScheme(){
|
||||
Normal = Application.Driver.MakeAttribute(Color.White,Color.Black),
|
||||
HotFocus = Application.Driver.MakeAttribute(Color.White,Color.Black)
|
||||
};
|
||||
return tv;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds a simple table of string columns with the requested number of columns and rows
|
||||
/// </summary>
|
||||
/// <param name="cols"></param>
|
||||
|
||||
Reference in New Issue
Block a user