From 1024f073b2ad2f30bcebd4e312a7b8bceda63225 Mon Sep 17 00:00:00 2001 From: Charlie Kindel Date: Fri, 29 May 2020 17:41:49 -0600 Subject: [PATCH] Fixing many clipping issues (#580) * almost got clip rect working * fixes many bugs related to clipping incl #399 * Merge tweaks. --- Terminal.Gui/Core/ConsoleDriver.cs | 97 ++++++++++++------ Terminal.Gui/Core/View.cs | 15 ++- Terminal.Gui/Core/Window.cs | 17 +++- Terminal.Gui/Views/Button.cs | 61 ++++++------ Terminal.Gui/Views/FrameView.cs | 12 ++- Terminal.Gui/Views/RadioGroup.cs | 2 +- Terminal.Gui/Views/ScrollView.cs | 9 +- UICatalog/Scenarios/Buttons.cs | 4 +- UICatalog/Scenarios/MessageBoxes.cs | 3 - UICatalog/Scenarios/Progress.cs | 5 +- UICatalog/Scenarios/Scrolling.cs | 103 ++++++++++++++++++++ UICatalog/Scenarios/WindowsAndFrameViews.cs | 42 +++++--- UICatalog/UICatalog.cs | 4 +- 13 files changed, 278 insertions(+), 96 deletions(-) create mode 100644 UICatalog/Scenarios/Scrolling.cs diff --git a/Terminal.Gui/Core/ConsoleDriver.cs b/Terminal.Gui/Core/ConsoleDriver.cs index 726f6d2ff..fb3015893 100644 --- a/Terminal.Gui/Core/ConsoleDriver.cs +++ b/Terminal.Gui/Core/ConsoleDriver.cs @@ -4,10 +4,13 @@ // Authors: // Miguel de Icaza (miguel@gnome.org) // +// Define this to enable diagnostics drawing for Window Frames +//#define DRAW_WINDOW_FRAME_DIAGNOSTICS using NStack; using System; using System.Runtime.CompilerServices; + namespace Terminal.Gui { /// @@ -547,6 +550,17 @@ namespace Terminal.Gui { } } +#if DRAW_WINDOW_FRAME_DIAGNOSTICS + const char leftChar = 'L'; + const char rightChar = 'R'; + const char topChar = 'T'; + const char bottomChar = 'B'; +#else + const char leftChar = clearChar; + const char rightChar = clearChar; + const char topChar = clearChar; + const char bottomChar = clearChar; +#endif /// /// Draws a frame for a window with padding aand n optional visible border inside the padding. /// @@ -565,11 +579,22 @@ namespace Terminal.Gui { AddRune (ch); } + // fwidth is count of hLine chars int fwidth = (int)(region.Width - (paddingRight + paddingLeft)); + + // fheight is count of vLine chars int fheight = (int)(region.Height - (paddingBottom + paddingTop)); - int fleft = region.X + paddingLeft; + + // fleft is location of left frame line + int fleft = region.X + paddingLeft - 1; + + // fright is location of right frame line int fright = fleft + fwidth + 1; - int ftop = region.Y + paddingTop; + + // ftop is location of top frame line + int ftop = region.Y + paddingTop - 1; + + // fbottom is locaiton of bottom frame line int fbottom = ftop + fheight + 1; Rune hLine = border ? HLine : clearChar; @@ -582,33 +607,33 @@ namespace Terminal.Gui { // Outside top if (paddingTop > 1) { for (int r = region.Y; r < ftop; r++) { - for (int c = region.X; c <= fright + paddingRight; c++) { - AddRuneAt (c, r, clearChar); + for (int c = region.X; c < region.X + region.Width; c++) { + AddRuneAt (c, r, topChar); } } } // Outside top-left - for (int c = region.X; c <= fleft; c++) { - AddRuneAt (c, ftop, clearChar); + for (int c = region.X; c < fleft; c++) { + AddRuneAt (c, ftop, leftChar); } // Frame top-left corner - AddRuneAt (fleft, ftop, paddingTop >= 0 ? (paddingLeft >= 0 ? uLCorner : hLine) : clearChar); + AddRuneAt (fleft, ftop, paddingTop >= 0 ? (paddingLeft >= 0 ? uLCorner : hLine) : leftChar); // Frame top - for (int c = fleft + 1; c <= fright; c++) { - AddRuneAt (c, ftop, paddingTop > 0 ? hLine : clearChar); + for (int c = fleft + 1; c < fleft + 1 + fwidth; c++) { + AddRuneAt (c, ftop, paddingTop > 0 ? hLine : topChar); } // Frame top-right corner if (fright > fleft) { - AddRuneAt (fright, ftop, paddingTop >= 0 ? (paddingRight >= 0 ? uRCorner : hLine) : clearChar); + AddRuneAt (fright, ftop, paddingTop >= 0 ? (paddingRight >= 0 ? uRCorner : hLine) : rightChar); } // Outside top-right corner for (int c = fright + 1; c < fright + paddingRight; c++) { - AddRuneAt (c, ftop, clearChar); + AddRuneAt (c, ftop, rightChar); } // Left, Fill, Right @@ -616,11 +641,11 @@ namespace Terminal.Gui { for (int r = ftop + 1; r < fbottom; r++) { // Outside left for (int c = region.X; c < fleft; c++) { - AddRuneAt (c, r, clearChar); + AddRuneAt (c, r, leftChar); } // Frame left - AddRuneAt (fleft, r, paddingLeft > 0 ? vLine : clearChar); + AddRuneAt (fleft, r, paddingLeft > 0 ? vLine : leftChar); // Fill if (fill) { @@ -631,44 +656,54 @@ namespace Terminal.Gui { // Frame right if (fright > fleft) { - AddRuneAt (fright, r, paddingRight > 0 ? vLine : clearChar); +#if DRAW_WINDOW_FRAME_DIAGNOSTICS + var v = (char)(((int)'0') + ((r - ftop) % 10)); // vLine; +#else + var v = vLine; +#endif + AddRuneAt (fright, r, paddingRight > 0 ? v : rightChar); } // Outside right for (int c = fright + 1; c < fright + paddingRight; c++) { - AddRuneAt (c, r, clearChar); + AddRuneAt (c, r, rightChar); } } // Outside Bottom - for (int c = region.X; c < fleft; c++) { - AddRuneAt (c, fbottom, clearChar); + for (int c = region.X; c < region.X + region.Width; c++) { + AddRuneAt (c, fbottom, leftChar); } // Frame bottom-left - AddRuneAt (fleft, fbottom, paddingLeft > 0 ? lLCorner : clearChar); + AddRuneAt (fleft, fbottom, paddingLeft > 0 ? lLCorner : leftChar); if (fright > fleft) { // Frame bottom for (int c = fleft + 1; c < fright; c++) { - AddRuneAt (c, fbottom, paddingBottom > 0 ? hLine : clearChar); +#if DRAW_WINDOW_FRAME_DIAGNOSTICS + var h = (char)(((int)'0') + ((c - fleft) % 10)); // hLine; +#else + var h = hLine; +#endif + AddRuneAt (c, fbottom, paddingBottom > 0 ? h : bottomChar); } // Frame bottom-right - AddRuneAt (fright, fbottom, paddingRight > 0 ? (paddingBottom > 0 ? lRCorner : hLine) : clearChar); + AddRuneAt (fright, fbottom, paddingRight > 0 ? (paddingBottom > 0 ? lRCorner : hLine) : rightChar); } // Outside right for (int c = fright + 1; c < fright + paddingRight; c++) { - AddRuneAt (c, fbottom, clearChar); + AddRuneAt (c, fbottom, rightChar); } } // Out bottom - ensure top is always drawn if we overlap if (paddingBottom > 0) { for (int r = fbottom + 1; r < fbottom + paddingBottom; r++) { - for (int c = region.X; c <= fright + paddingRight; c++) { - AddRuneAt (c, r, clearChar); + for (int c = region.X; c < region.X + region.Width; c++) { + AddRuneAt (c, r, bottomChar); } } } @@ -677,17 +712,19 @@ namespace Terminal.Gui { /// /// Draws a frame on the specified region with the specified padding around the frame. /// - /// Region where the frame will be drawn.. + /// Screen relative region where the frame will be drawn. /// Padding to add on the sides. /// If set to true it will clear the contents with the current color, otherwise the contents will be left untouched. - /// This is a legacy/depcrecated API. Use . - /// A padding value of 0 means there is actually a 1 cell border. + /// This API has been superceded by . + /// This API is equivlalent to calling DrawWindowFrame(Rect, p - 1, p - 1, p - 1, p - 1). In other words, + /// A padding value of 0 means there is actually a one cell border. + /// public virtual void DrawFrame (Rect region, int padding, bool fill) { - // DrawFrame assumes the frame is always at least one row/col thick - // DrawWindowFrame assumes a padding of 0 means NO padding - padding++; - DrawWindowFrame (new Rect (region.X - 1, region.Y - 1, region.Width, region.Height), padding, padding, padding, padding, fill: fill); + // DrawFrame assumes the border is always at least one row/col thick + // DrawWindowFrame assumes a padding of 0 means NO padding and no frame + DrawWindowFrame (new Rect (region.X, region.Y, region.Width, region.Height), + padding + 1, padding + 1, padding + 1, padding + 1, fill: fill); } diff --git a/Terminal.Gui/Core/View.cs b/Terminal.Gui/Core/View.cs index 808d829b0..b426a9a06 100644 --- a/Terminal.Gui/Core/View.cs +++ b/Terminal.Gui/Core/View.cs @@ -665,7 +665,7 @@ namespace Terminal.Gui { { var bscreen = RectToScreen (rect); var previous = Driver.Clip; - Driver.Clip = ScreenClip (RectToScreen (Bounds)); + Driver.Clip = ScreenClip (RectToScreen (Bounds)); return previous; } @@ -678,8 +678,7 @@ namespace Terminal.Gui { public void DrawFrame (Rect rect, int padding = 0, bool fill = false) { var scrRect = RectToScreen (rect); - var savedClip = Driver.Clip; - Driver.Clip = ScreenClip (RectToScreen (Bounds)); + var savedClip = ClipToBounds (); Driver.DrawFrame (scrRect, padding, fill); Driver.Clip = savedClip; } @@ -890,7 +889,15 @@ namespace Terminal.Gui { if (view.layoutNeeded) view.LayoutSubviews (); Application.CurrentView = view; - view.Redraw (view.Bounds); + + // Ensure we don't make the Driver's clip rect any bigger + if (Driver.Clip.IsEmpty || Driver.Clip.Contains(RectToScreen (view.Frame))) { + var savedClip = view.ClipToBounds (); + view.Redraw (view.Bounds); + Driver.Clip = savedClip; + } else { + view.Redraw (view.Bounds); + } } view.NeedDisplay = Rect.Empty; view.childNeedsDisplay = false; diff --git a/Terminal.Gui/Core/Window.cs b/Terminal.Gui/Core/Window.cs index 548acf3ed..3544fc2e5 100644 --- a/Terminal.Gui/Core/Window.cs +++ b/Terminal.Gui/Core/Window.cs @@ -40,6 +40,7 @@ namespace Terminal.Gui { Driver.AddRune ('x'); } } + base.Redraw (region); } #endif } @@ -153,16 +154,23 @@ namespace Terminal.Gui { /// public override void Redraw (Rect bounds) { + //var padding = 0; Application.CurrentView = this; - var scrRect = RectToScreen (new Rect (0, 0, Frame.Width, Frame.Height)); - var savedClip = Driver.Clip; - Driver.Clip = ScreenClip (RectToScreen (Bounds)); + var scrRect = RectToScreen (new Rect(0, 0, Frame.Width, Frame.Height)); + // BUGBUG: Why do we draw the frame twice? This call is here to clear the content area, I think. Why not just clear that area? if (NeedDisplay != null && !NeedDisplay.IsEmpty) { Driver.SetAttribute (ColorScheme.Normal); Driver.DrawFrame (scrRect, padding, true); } - contentView.Redraw (contentView.Bounds); + + if (Driver.Clip.IsEmpty || Driver.Clip.Contains (contentView.RectToScreen (contentView.Frame))) { + var savedClip = ClipToBounds (); + contentView.Redraw (contentView.Bounds); + Driver.Clip = savedClip; + } else { + contentView.Redraw (contentView.Bounds); + } ClearNeedsDisplay (); Driver.SetAttribute (ColorScheme.Normal); Driver.DrawFrame (scrRect, padding, false); @@ -170,7 +178,6 @@ namespace Terminal.Gui { if (HasFocus) Driver.SetAttribute (ColorScheme.HotNormal); Driver.DrawWindowTitle (scrRect, Title, padding, padding, padding, padding); - Driver.Clip = savedClip; Driver.SetAttribute (ColorScheme.Normal); } diff --git a/Terminal.Gui/Views/Button.cs b/Terminal.Gui/Views/Button.cs index 774050634..54298d093 100644 --- a/Terminal.Gui/Views/Button.cs +++ b/Terminal.Gui/Views/Button.cs @@ -39,6 +39,7 @@ namespace Terminal.Gui { get => is_default; set { is_default = value; + SetWidthHeight (Text, is_default); Update (); } } @@ -65,20 +66,12 @@ namespace Terminal.Gui { public Button (ustring text, bool is_default = false) : base () { CanFocus = true; + Text = text ?? string.Empty; this.IsDefault = is_default; - Text = text; int w = SetWidthHeight (text, is_default); Frame = new Rect (0, 0, w, 1); } - int SetWidthHeight (ustring text, bool is_default) - { - int w = text.Length + 4 + (is_default ? 2 : 0); - Width = w; - Height = 1; - return w; - } - /// /// Initializes a new instance of at the given coordinates, based on the given text /// @@ -91,6 +84,35 @@ namespace Terminal.Gui { /// The button's text public Button (int x, int y, ustring text) : this (x, y, text, false) { } + /// + /// Initializes a new instance of at the given coordinates, based on the given text, and with the specified value + /// + /// + /// If the value for is_default is true, a special + /// decoration is used, and the enter key on a + /// dialog would implicitly activate this button. + /// + /// X position where the button will be shown. + /// Y position where the button will be shown. + /// The button's text + /// If set, this makes the button the default button in the current view, which means that if the user presses return on a view that does not handle return, it will be treated as if he had clicked on the button + public Button (int x, int y, ustring text, bool is_default) + : base (new Rect (x, y, text.Length + 4 + (is_default ? 2 : 0), 1)) + { + CanFocus = true; + Text = text ?? string.Empty; + this.IsDefault = is_default; + } + + + int SetWidthHeight (ustring text, bool is_default) + { + int w = text.Length + 4 + (is_default ? 2 : 0); + Width = w; + Height = 1; + return w; + } + /// /// The text displayed by this . /// @@ -129,27 +151,6 @@ namespace Terminal.Gui { SetNeedsDisplay (); } - /// - /// Initializes a new instance of at the given coordinates, based on the given text, and with the specified value - /// - /// - /// If the value for is_default is true, a special - /// decoration is used, and the enter key on a - /// dialog would implicitly activate this button. - /// - /// X position where the button will be shown. - /// Y position where the button will be shown. - /// The button's text - /// If set, this makes the button the default button in the current view, which means that if the user presses return on a view that does not handle return, it will be treated as if he had clicked on the button - public Button (int x, int y, ustring text, bool is_default) - : base (new Rect (x, y, text.Length + 4 + (is_default ? 2 : 0), 1)) - { - CanFocus = true; - - this.IsDefault = is_default; - Text = text; - } - /// public override void Redraw (Rect region) { diff --git a/Terminal.Gui/Views/FrameView.cs b/Terminal.Gui/Views/FrameView.cs index 93fecf4b5..a08646ba0 100644 --- a/Terminal.Gui/Views/FrameView.cs +++ b/Terminal.Gui/Views/FrameView.cs @@ -137,14 +137,19 @@ namespace Terminal.Gui { var padding = 0; Application.CurrentView = this; var scrRect = RectToScreen (new Rect (0, 0, Frame.Width, Frame.Height)); - var savedClip = Driver.Clip; - Driver.Clip = ScreenClip (RectToScreen (Bounds)); if (NeedDisplay != null && !NeedDisplay.IsEmpty) { Driver.SetAttribute (ColorScheme.Normal); Driver.DrawFrame (scrRect, padding, true); } - contentView.Redraw (contentView.Bounds); + + if (Driver.Clip.IsEmpty || Driver.Clip.Contains (contentView.RectToScreen (contentView.Frame))) { + var savedClip = ClipToBounds (); + contentView.Redraw (contentView.Bounds); + Driver.Clip = savedClip; + } else { + contentView.Redraw (contentView.Bounds); + } ClearNeedsDisplay (); Driver.SetAttribute (ColorScheme.Normal); Driver.DrawFrame (scrRect, padding, false); @@ -152,7 +157,6 @@ namespace Terminal.Gui { if (HasFocus) Driver.SetAttribute (ColorScheme.HotNormal); Driver.DrawWindowTitle (scrRect, Title, padding, padding, padding, padding); - Driver.Clip = savedClip; Driver.SetAttribute (ColorScheme.Normal); } } diff --git a/Terminal.Gui/Views/RadioGroup.cs b/Terminal.Gui/Views/RadioGroup.cs index 431e11d3f..c86ea2259 100644 --- a/Terminal.Gui/Views/RadioGroup.cs +++ b/Terminal.Gui/Views/RadioGroup.cs @@ -110,13 +110,13 @@ namespace Terminal.Gui { /// public override void Redraw (Rect region) { - base.Redraw (region); for (int i = 0; i < radioLabels.Length; i++) { Move (0, i); Driver.SetAttribute (ColorScheme.Normal); Driver.AddStr (i == selected ? "(o) " : "( ) "); DrawHotString (radioLabels [i], HasFocus && i == cursor, ColorScheme); } + base.Redraw (region); } /// diff --git a/Terminal.Gui/Views/ScrollView.cs b/Terminal.Gui/Views/ScrollView.cs index 64689a437..3315a3691 100644 --- a/Terminal.Gui/Views/ScrollView.cs +++ b/Terminal.Gui/Views/ScrollView.cs @@ -401,11 +401,14 @@ namespace Terminal.Gui { public override void Redraw(Rect region) { SetViewsNeedsDisplay (); - var oldClip = ClipToBounds (); Driver.SetAttribute (ColorScheme.Normal); Clear (); - base.Redraw(region); - Driver.Clip = oldClip; + + var savedClip = ClipToBounds (); + contentView.Redraw (contentView.Bounds); + vertical.Redraw (vertical.Bounds); + horizontal.Redraw (vertical.Bounds); + Driver.Clip = savedClip; Driver.SetAttribute (ColorScheme.Normal); } diff --git a/UICatalog/Scenarios/Buttons.cs b/UICatalog/Scenarios/Buttons.cs index dddd9921c..76756fa53 100644 --- a/UICatalog/Scenarios/Buttons.cs +++ b/UICatalog/Scenarios/Buttons.cs @@ -75,7 +75,9 @@ namespace UICatalog { y += 2; // BUGBUG: Buttons don't support specifying hotkeys with _?!? - Win.Add (button = new Button (10, y, "Te_xt Changer") { + Win.Add (button = new Button ("Te_xt Changer") { + X = 10, + Y = y }); button.Clicked = () => button.Text += $"{y++}"; diff --git a/UICatalog/Scenarios/MessageBoxes.cs b/UICatalog/Scenarios/MessageBoxes.cs index e21720e66..f54f0d6f4 100644 --- a/UICatalog/Scenarios/MessageBoxes.cs +++ b/UICatalog/Scenarios/MessageBoxes.cs @@ -7,7 +7,6 @@ namespace UICatalog { [ScenarioMetadata (Name: "MessageBoxes", Description: "Demonstrates how to use MessageBoxes")] [ScenarioCategory ("Controls")] [ScenarioCategory ("Dialogs")] - [ScenarioCategory ("Bug Repro")] class MessageBoxes : Scenario { public override void Setup () { @@ -110,7 +109,6 @@ namespace UICatalog { var styleRadioGroup = new RadioGroup (new [] { "_Query", "_Error" } ) { X = Pos.Right (label) + 1, Y = Pos.Top (label), - Width = 5, // BUGBUG: This should cause clipping! }; frame.Add (styleRadioGroup); @@ -132,7 +130,6 @@ namespace UICatalog { ColorScheme = Colors.Error, }; - // BUGBUG: Why is this button not centered??? var showMessageBoxButton = new Button ("Show MessageBox") { X = Pos.Center(), Y = Pos.Bottom (frame) + 2 , diff --git a/UICatalog/Scenarios/Progress.cs b/UICatalog/Scenarios/Progress.cs index 6351de13c..7ef28f92e 100644 --- a/UICatalog/Scenarios/Progress.cs +++ b/UICatalog/Scenarios/Progress.cs @@ -41,7 +41,7 @@ namespace UICatalog { LeftFrame = new FrameView ("Settings") { X = 0, Y = 0, - Height = Dim.Percent (100) + 1, // BUGBUG: This +1 should not be needed + Height = Dim.Percent (100), Width = Dim.Percent (25) }; var lbl = new Label (1, 1, "Tick every (ms):"); @@ -223,14 +223,13 @@ namespace UICatalog { var startBoth = new Button ("Start Both") { X = Pos.Center (), - Y = Pos.AnchorEnd () - 1, + Y = Pos.Bottom(mainLoopTimeoutDemo) + 1, }; startBoth.Clicked = () => { systemTimerDemo.Start (); mainLoopTimeoutDemo.Start (); }; Win.Add (startBoth); - } protected override void Dispose (bool disposing) diff --git a/UICatalog/Scenarios/Scrolling.cs b/UICatalog/Scenarios/Scrolling.cs new file mode 100644 index 000000000..c4ad66b47 --- /dev/null +++ b/UICatalog/Scenarios/Scrolling.cs @@ -0,0 +1,103 @@ +using System; +using Terminal.Gui; + +namespace UICatalog { + [ScenarioMetadata (Name: "Scrolling", Description: "Demonstrates ScrollView etc...")] + [ScenarioCategory ("Controls")] + [ScenarioCategory ("Bug Repro")] + + class Scrolling : Scenario { + public override void Setup () + { + var label = new Label ("ScrollView (new Rect (2, 2, 50, 20)) with a 200, 100 ContentSize...") { + X = 0, Y = 0, + ColorScheme = Colors.Dialog + }; + Win.Add (label); + + // BUGBUG: ScrollView only supports Absolute Positioning (#72) + var scrollView = new ScrollView (new Rect (2, 2, 50, 20)); + scrollView.ColorScheme = Colors.TopLevel; + scrollView.ContentSize = new Size (200, 100); + //ContentOffset = new Point (0, 0), + scrollView.ShowVerticalScrollIndicator = true; + scrollView.ShowHorizontalScrollIndicator = true; + + const string rule = "|123456789"; + var horizontalRuler = new Label ("") { + X = 0, + Y = 0, + Width = Dim.Fill (1), // BUGBUG: I don't think this should be needed; DimFill() should respect container's frame. X does. + ColorScheme = Colors.Error + }; + scrollView.Add (horizontalRuler); + const string vrule = "|\n1\n2\n3\n4\n5\n6\n7\n8\n9\n"; + + var verticalRuler = new Label ("") { + X = 0, + Y = 0, + Width = 1, + Height = Dim.Fill (), + ColorScheme = Colors.Error + }; + scrollView.Add (verticalRuler); + + Application.Resized += (sender, a) => { + horizontalRuler.Text = rule.Repeat ((int)Math.Ceiling ((double)(horizontalRuler.Bounds.Width) / (double)rule.Length)) [0..(horizontalRuler.Bounds.Width)]; + verticalRuler.Text = vrule.Repeat ((int)Math.Ceiling ((double)(verticalRuler.Bounds.Height * 2) / (double)rule.Length)) [0..(verticalRuler.Bounds.Height * 2)]; + }; + + scrollView.Add (new Button ("Press me!") { + X = 3, + Y = 3, + Clicked = () => MessageBox.Query (20, 7, "MessageBox", "Neat?", "Yes", "No") + }); + + scrollView.Add (new Button ("A very long button. Should be wide enough to demo clipping!") { + X = 3, + Y = 4, + Width = 50, + Clicked = () => MessageBox.Query (20, 7, "MessageBox", "Neat?", "Yes", "No") + }); + + scrollView.Add (new TextField ("This is a test of...") { + X = 3, + Y = 5, + Width = 50, + ColorScheme = Colors.Dialog + }); + + scrollView.Add (new TextField ("... the emergency broadcast sytem.") { + X = 3, + Y = 10, + Width = 50, + ColorScheme = Colors.Dialog + }); + + scrollView.Add (new TextField ("Last line") { + X = 3, + Y = 99, + Width = 50, + ColorScheme = Colors.Dialog + }); + + // Demonstrate AnchorEnd - Button is anchored to bottom/right + var anchorButton = new Button ("Bottom Right") { + Y = Pos.AnchorEnd () - 1, + }; + // TODO: Use Pos.Width instead of (Right-Left) when implemented (#502) + anchorButton.X = Pos.AnchorEnd () - (Pos.Right (anchorButton) - Pos.Left (anchorButton)); + anchorButton.Clicked = () => { + // Ths demonstrates how to have a dynamically sized button + // Each time the button is clicked the button's text gets longer + // The call to Win.LayoutSubviews causes the Computed layout to + // get updated. + anchorButton.Text += "!"; + Win.LayoutSubviews (); + }; + scrollView.Add (anchorButton); + + Win.Add (scrollView); + } + } +} \ No newline at end of file diff --git a/UICatalog/Scenarios/WindowsAndFrameViews.cs b/UICatalog/Scenarios/WindowsAndFrameViews.cs index 5d575e06b..962510508 100644 --- a/UICatalog/Scenarios/WindowsAndFrameViews.cs +++ b/UICatalog/Scenarios/WindowsAndFrameViews.cs @@ -30,22 +30,42 @@ namespace UICatalog { public override void Setup () { + static int About () + { + //return MessageBox.Query (50, 10, "About UI Catalog", "UI Catalog is a comprehensive sample library for Terminal.Gui", "Ok") + + var about = new Window (new Rect (0, 0, 50, 10), "About UI catalog", 0) { + X = Pos.Center (), + Y = Pos.Center (), + Width = 50, + Height = 10, + LayoutStyle = LayoutStyle.Computed, + ColorScheme = Colors.Error, + + }; + //about.Add (new Label ("UI Catalog is a comprehensive sample library for Terminal.Gui")); + + Application.Run (about); + return 0; + + } + int margin = 2; - int padding = 0; - int height = 10; + int padding = 1; + int contentHeight = 7; var listWin = new List (); Win = new Window ($"{listWin.Count} - Scenario: {GetName ()}", padding) { X = Pos.Center (), Y = 1, Width = Dim.Fill (10), - Height = Dim.Percent (15), + Height = Dim.Percent (15) }; Win.ColorScheme = Colors.Dialog; - Win.Add (new Button ("Press me! (Y = 0)") { + Win.Add (new Button ($"Padding of container is {padding}") { X = Pos.Center (), Y = 0, ColorScheme = Colors.Error, - Clicked = () => MessageBox.ErrorQuery (30, 10, Win.Title.ToString (), "Neat?", "Yes", "No") + Clicked = () => About() }); Win.Add (new Button ("Press ME! (Y = Pos.AnchorEnd(1))") { X = Pos.Center (), @@ -55,13 +75,13 @@ namespace UICatalog { Top.Add (Win); listWin.Add (Win); - for (var i = 0; i < 2; i++) { + for (var i = 0; i < 3; i++) { Window win = null; - win = new Window ($"{listWin.Count} - Loop {i}", padding) { + win = new Window ($"{listWin.Count} - Window Loop - padding = {i}", i) { X = margin, Y = Pos.Bottom (listWin.Last ()) + (margin), Width = Dim.Fill (margin), - Height = height, + Height = contentHeight + (i*2) + 2, }; win.ColorScheme = Colors.Dialog; win.Add (new Button ("Press me! (Y = 0)") { @@ -101,14 +121,14 @@ namespace UICatalog { X = margin, Y = Pos.Bottom (listWin.Last ()) + (margin / 2), Width = Dim.Fill (margin), - Height = height, + Height = contentHeight + 2, // 2 for default padding }; frame.ColorScheme = Colors.Dialog; - frame.Add (new Button ("Press me! (Y = 0)") { + frame.Add (new Label ("This is a Label! (Y = 0)") { X = Pos.Center (), Y = 0, ColorScheme = Colors.Error, - Clicked = () => MessageBox.ErrorQuery (30, 10, frame.Title.ToString (), "Neat?", "Yes", "No") + //Clicked = () => MessageBox.ErrorQuery (30, 10, frame.Title.ToString (), "Neat?", "Yes", "No") }); var subWinofFV = new Window ("this is a Sub-Window") { X = Pos.Percent (0), diff --git a/UICatalog/UICatalog.cs b/UICatalog/UICatalog.cs index 8a1b52377..62e8b7ec0 100644 --- a/UICatalog/UICatalog.cs +++ b/UICatalog/UICatalog.cs @@ -92,7 +92,7 @@ namespace UICatalog { new MenuBarItem ("_File", new MenuItem [] { new MenuItem ("_Quit", "", () => Application.RequestStop() ) }), - new MenuBarItem ("_About...", "About this app", () => MessageBox.Query (0, 10, "About UI Catalog", "UI Catalog is a comprehensive sample library for Terminal.Gui", "Ok")), + new MenuBarItem ("_About...", "About this app", () => MessageBox.Query (50, 10, "About UI Catalog", "UI Catalog is a comprehensive sample library for Terminal.Gui", "Ok")), }); _leftPane = new Window ("Categories") { @@ -163,6 +163,8 @@ namespace UICatalog { } }), }); + + } ///