Skip to content

Commit

Permalink
Merge branch 'main' of tig:migueldeicaza/gui.cs
Browse files Browse the repository at this point in the history
  • Loading branch information
tig committed May 13, 2021
2 parents 1582310 + 4059c7e commit b71f7d2
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 35 deletions.
2 changes: 1 addition & 1 deletion ReactiveExample/ReactiveExample.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@
<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" Version="13.3.1" />
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion Terminal.Gui/Terminal.Gui.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
93 changes: 61 additions & 32 deletions Terminal.Gui/Views/TableView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -300,10 +300,15 @@ private void RenderHeaderOverline(int row,int availableWidth, ColumnToRender[] c
// 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);
Expand All @@ -324,45 +329,26 @@ private void RenderHeaderMidline(int row, ColumnToRender[] columnsToRender)
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:
Expand All @@ -385,6 +371,11 @@ private void RenderHeaderUnderline(int row,int availableWidth, ColumnToRender[]
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);
Expand All @@ -397,11 +388,15 @@ private void RenderRow(int row, int rowToRender, ColumnToRender[] columnsToRende
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);

Expand All @@ -418,13 +413,17 @@ private void RenderRow(int row, int rowToRender, ColumnToRender[] columnsToRende
// 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
Expand Down Expand Up @@ -1019,21 +1018,26 @@ private IEnumerable<ColumnToRender> CalculateViewport (Rect bounds, int padding
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;
}
}
Expand Down Expand Up @@ -1215,6 +1219,17 @@ public class TableStyle {
/// </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>
Expand Down Expand Up @@ -1254,11 +1269,25 @@ internal class ColumnToRender {
/// </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>
Expand Down
11 changes: 11 additions & 0 deletions UICatalog/Scenarios/TableEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class TableEditor : Scenario
private MenuItem miHeaderUnderline;
private MenuItem miCellLines;
private MenuItem miFullRowSelect;
private MenuItem miExpandLastColumn;

public override void Setup ()
{
Expand Down Expand Up @@ -51,6 +52,7 @@ public override void Setup ()
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()),
Expand Down Expand Up @@ -181,6 +183,15 @@ private void ToggleFullRowSelect ()
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;
Expand Down
87 changes: 86 additions & 1 deletion UnitTests/TableViewTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,92 @@ public void GetAllSelectedCells_TwoIsolatedSelections_ReturnsSix()
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>
Expand Down

0 comments on commit b71f7d2

Please sign in to comment.