merge with master

This commit is contained in:
Charlie Kindel
2020-07-06 08:20:39 -07:00
12 changed files with 430 additions and 255 deletions

View File

@@ -237,12 +237,13 @@ static class Demo {
//
static void Editor ()
{
var tframe = Application.Top.Frame;
Application.Top.RemoveAll ();
Application.Init ();
var ntop = Application.Top;
var menu = new MenuBar (new MenuBarItem [] {
new MenuBarItem ("_File", new MenuItem [] {
new MenuItem ("_Close", "", () => { if (Quit ()) {Application.RequestStop (); } }),
new MenuItem ("_Close", "", () => { if (Quit ()) { running = MainApp; Application.RequestStop (); } }),
}),
new MenuBarItem ("_Edit", new MenuItem [] {
new MenuItem ("_Copy", "", null),
@@ -267,15 +268,13 @@ static class Demo {
};
ntop.Add (win);
var text = new TextView (new Rect (0, 0, tframe.Width - 2, tframe.Height - 3));
var text = new TextView () { X = 0, Y = 0, Width = Dim.Fill (), Height = Dim.Fill () };
if (fname != null)
text.Text = System.IO.File.ReadAllText (fname);
win.Add (text);
Application.Run (ntop, false);
Application.Top.RemoveAll ();
Main ();
}
static bool Quit ()
@@ -450,20 +449,22 @@ static class Demo {
static void ComboBoxDemo ()
{
IList<string> items = new List<string> ();
foreach (var dir in new [] { "/etc", @"\windows\System32" }) {
//TODO: Duplicated code in ListsAndCombos.cs Consider moving to shared assembly
var items = new List<ustring> ();
foreach (var dir in new [] { "/etc", @$"{Environment.GetEnvironmentVariable ("SystemRoot")}\System32" }) {
if (Directory.Exists (dir)) {
items = Directory.GetFiles (dir).Union (Directory.GetDirectories (dir))
.Select (Path.GetFileName)
.Where (x => char.IsLetterOrDigit (x [0]))
.OrderBy (x => x).ToList ();
.OrderBy (x => x).Select (x => ustring.Make (x)).ToList ();
}
}
var list = new ComboBox () { X = 0, Y = 0, Width = Dim.Fill(), Height = Dim.Fill() };
list.SetSource(items.ToList());
list.SelectedItemChanged += (object sender, ustring text) => { Application.RequestStop (); };
var list = new ComboBox () { Width = Dim.Fill(), Height = Dim.Fill() };
list.SetSource(items);
list.OpenSelectedItem += (ListViewItemEventArgs text) => { Application.RequestStop (); };
var d = new Dialog ("Select source file", 40, 12) { list };
var d = new Dialog () { Title = "Select source file", Width = Dim.Percent (50), Height = Dim.Percent (50) };
d.Add (list);
Application.Run (d);
MessageBox.Query (60, 10, "Selected file", list.Text.ToString() == "" ? "Nothing selected" : list.Text.ToString(), "Ok");
@@ -534,11 +535,20 @@ static class Demo {
}
#endregion
public static Action running = MainApp;
static void Main ()
{
while (running != null) {
running.Invoke ();
}
Application.Shutdown ();
}
public static Label ml;
public static MenuBar menu;
public static CheckBox menuKeysStyle;
public static CheckBox menuAutoMouseNav;
static void Main ()
static void MainApp ()
{
if (Debugger.IsAttached)
CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.GetCultureInfo ("en-US");
@@ -578,14 +588,14 @@ static class Demo {
menu = new MenuBar (new MenuBarItem [] {
new MenuBarItem ("_File", new MenuItem [] {
new MenuItem ("Text _Editor Demo", "", () => { Editor (); }),
new MenuItem ("Text _Editor Demo", "", () => { running = Editor; Application.RequestStop (); }),
new MenuItem ("_New", "Creates new file", NewFile),
new MenuItem ("_Open", "", Open),
new MenuItem ("_Hex", "", () => ShowHex (top)),
new MenuItem ("_Close", "", () => Close ()),
new MenuItem ("_Disabled", "", () => { }, () => false),
null,
new MenuItem ("_Quit", "", () => { if (Quit ()) top.Running = false; })
new MenuItem ("_Quit", "", () => { if (Quit ()) { running = null; top.Running = false; } })
}),
new MenuBarItem ("_Edit", new MenuItem [] {
new MenuItem ("_Copy", "", Copy),
@@ -648,9 +658,8 @@ static class Demo {
new StatusItem(Key.F1, "~F1~ Help", () => Help()),
new StatusItem(Key.F2, "~F2~ Load", Load),
new StatusItem(Key.F3, "~F3~ Save", Save),
new StatusItem(Key.ControlQ, "~^Q~ Quit", () => { if (Quit ()) top.Running = false; }),
}) {
};
new StatusItem(Key.ControlQ, "~^Q~ Quit", () => { if (Quit ()) { running = null; top.Running = false; } })
});
win.Add (drag, dragText);
@@ -671,7 +680,7 @@ static class Demo {
top.Add (win);
//top.Add (menu);
top.Add (menu, statusBar);
Application.Run ();
Application.Run (top, false);
}
private static void Win_KeyPress (View.KeyEventEventArgs e)

View File

@@ -589,16 +589,23 @@ namespace Terminal.Gui {
MainLoop.MainIteration ();
Iteration?.Invoke ();
} else if (wait == false)
} else if (wait == false) {
return;
if (state.Toplevel.NeedDisplay != null && (!state.Toplevel.NeedDisplay.IsEmpty || state.Toplevel.childNeedsDisplay)) {
}
if (state.Toplevel != Top && (!Top.NeedDisplay.IsEmpty || Top.childNeedsDisplay)) {
Top.Redraw (Top.Bounds);
state.Toplevel.SetNeedsDisplay (state.Toplevel.Bounds);
}
if (!state.Toplevel.NeedDisplay.IsEmpty || state.Toplevel.childNeedsDisplay) {
state.Toplevel.Redraw (state.Toplevel.Bounds);
if (DebugDrawBounds)
if (DebugDrawBounds) {
DrawBounds (state.Toplevel);
}
state.Toplevel.PositionCursor ();
Driver.Refresh ();
} else
} else {
Driver.UpdateCursor ();
}
}
}

View File

@@ -56,7 +56,7 @@ namespace Terminal.Gui {
/// Gets or sets a value indicating whether this <see cref="Responder"/> has focus.
/// </summary>
/// <value><c>true</c> if has focus; otherwise, <c>false</c>.</value>
public virtual bool HasFocus { get; internal set; }
public virtual bool HasFocus { get; }
// Key handling
/// <summary>
@@ -161,7 +161,6 @@ namespace Terminal.Gui {
return false;
}
/// <summary>
/// Method invoked when a mouse event is generated
/// </summary>
@@ -195,8 +194,9 @@ namespace Terminal.Gui {
/// <summary>
/// Method invoked when a view gets focus.
/// </summary>
/// <param name="view">The view that is losing focus.</param>
/// <returns><c>true</c>, if the event was handled, <c>false</c> otherwise.</returns>
public virtual bool OnEnter ()
public virtual bool OnEnter (View view)
{
return false;
}
@@ -204,8 +204,9 @@ namespace Terminal.Gui {
/// <summary>
/// Method invoked when a view loses focus.
/// </summary>
/// <param name="view">The view that is getting focus.</param>
/// <returns><c>true</c>, if the event was handled, <c>false</c> otherwise.</returns>
public virtual bool OnLeave ()
public virtual bool OnLeave (View view)
{
return false;
}

View File

@@ -124,6 +124,16 @@ namespace Terminal.Gui {
TextFormatter textFormatter;
/// <summary>
/// Event fired when a subview is being added to this view.
/// </summary>
public Action<View> Added;
/// <summary>
/// Event fired when a subview is being removed from this view.
/// </summary>
public Action<View> Removed;
/// <summary>
/// Event fired when the view gets focus.
/// </summary>
@@ -552,6 +562,7 @@ namespace Terminal.Gui {
subviews = new List<View> ();
subviews.Add (view);
view.container = this;
OnAdded (view);
if (view.CanFocus)
CanFocus = true;
SetNeedsLayout ();
@@ -601,6 +612,7 @@ namespace Terminal.Gui {
var touched = view.Frame;
subviews.Remove (view);
view.container = null;
OnRemoved (view);
if (subviews.Count < 1)
this.CanFocus = false;
@@ -895,26 +907,31 @@ namespace Terminal.Gui {
}
}
bool hasFocus;
/// <inheritdoc/>
public override bool HasFocus {
get {
return base.HasFocus;
return hasFocus;
}
internal set {
if (base.HasFocus != value)
if (value)
OnEnter ();
else
OnLeave ();
SetNeedsDisplay ();
base.HasFocus = value;
}
// Remove focus down the chain of subviews if focus is removed
if (!value && focused != null) {
focused.OnLeave ();
focused.HasFocus = false;
focused = null;
}
void SetHasFocus (bool value, View view)
{
if (hasFocus != value) {
hasFocus = value;
}
if (value) {
OnEnter (view);
} else {
OnLeave (view);
}
SetNeedsDisplay ();
// Remove focus down the chain of subviews if focus is removed
if (!value && focused != null) {
focused.OnLeave (view);
focused.SetHasFocus (false, view);
focused = null;
}
}
@@ -925,35 +942,58 @@ namespace Terminal.Gui {
/// <summary>
/// Constructs.
/// </summary>
public FocusEventArgs () { }
/// <param name="view">The view that gets or loses focus.</param>
public FocusEventArgs (View view) { View = view; }
/// <summary>
/// Indicates if the current focus event has already been processed and the driver should stop notifying any other event subscriber.
/// Its important to set this value to true specially when updating any View's layout from inside the subscriber method.
/// </summary>
public bool Handled { get; set; }
/// <summary>
/// Indicates the current view that gets or loses focus.
/// </summary>
public View View { get; set; }
}
/// <summary>
/// Method invoked when a subview is being added to this view.
/// </summary>
/// <param name="view">The subview being added.</param>
public virtual void OnAdded (View view)
{
view.Added?.Invoke (this);
}
/// <summary>
/// Method invoked when a subview is being removed from this view.
/// </summary>
/// <param name="view">The subview being removed.</param>
public virtual void OnRemoved (View view)
{
view.Removed?.Invoke (this);
}
/// <inheritdoc/>
public override bool OnEnter ()
public override bool OnEnter (View view)
{
FocusEventArgs args = new FocusEventArgs ();
FocusEventArgs args = new FocusEventArgs (view);
Enter?.Invoke (args);
if (args.Handled)
return true;
if (base.OnEnter ())
if (base.OnEnter (view))
return true;
return false;
}
/// <inheritdoc/>
public override bool OnLeave ()
public override bool OnLeave (View view)
{
FocusEventArgs args = new FocusEventArgs ();
FocusEventArgs args = new FocusEventArgs (view);
Leave?.Invoke (args);
if (args.Handled)
return true;
if (base.OnLeave ())
if (base.OnLeave (view))
return true;
return false;
@@ -1125,10 +1165,11 @@ namespace Terminal.Gui {
throw new ArgumentException ("the specified view is not part of the hierarchy of this view");
if (focused != null)
focused.HasFocus = false;
focused.SetHasFocus (false, view);
var f = focused;
focused = view;
focused.HasFocus = true;
focused.SetHasFocus (true, f);
focused.EnsureFocus ();
// Send focus upwards
@@ -1322,7 +1363,7 @@ namespace Terminal.Gui {
continue;
}
if (w.CanFocus && focused_idx != -1) {
focused.HasFocus = false;
focused.SetHasFocus (false, w);
if (w != null && w.CanFocus)
w.FocusLast ();
@@ -1332,7 +1373,7 @@ namespace Terminal.Gui {
}
}
if (focused != null) {
focused.HasFocus = false;
focused.SetHasFocus (false, this);
focused = null;
}
return false;
@@ -1364,7 +1405,7 @@ namespace Terminal.Gui {
continue;
}
if (w.CanFocus && focused_idx != -1) {
focused.HasFocus = false;
focused.SetHasFocus (false, w);
if (w != null && w.CanFocus)
w.FocusFirst ();
@@ -1374,7 +1415,7 @@ namespace Terminal.Gui {
}
}
if (focused != null) {
focused.HasFocus = false;
focused.SetHasFocus (false, this);
focused = null;
}
return false;

View File

@@ -4,15 +4,10 @@
// Authors:
// Ross Ferguson (ross.c.ferguson@btinternet.com)
//
// TODO:
// LayoutComplete() resize Height implement
// Cursor rolls of end of list when Height = Dim.Fill() and list fills frame
//
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using NStack;
namespace Terminal.Gui {
@@ -33,7 +28,12 @@ namespace Terminal.Gui {
get => source;
set {
source = value;
SetNeedsDisplay ();
// Only need to refresh list if its been added to a container view
if(SuperView != null && SuperView.Subviews.Contains(this)) {
Search_Changed ("");
SetNeedsDisplay ();
}
}
}
@@ -46,34 +46,34 @@ namespace Terminal.Gui {
/// </remarks>
public void SetSource (IList source)
{
if (source == null)
if (source == null) {
Source = null;
else {
Source = MakeWrapper (source);
} else {
listview.SetSource (source);
Source = listview.Source;
}
}
/// <summary>
/// Changed event, raised when the selection has been confirmed.
/// This event is raised when the selected item in the <see cref="ComboBox"/> has changed.
/// </summary>
/// <remarks>
/// Client code can hook up to this event, it is
/// raised when the selection has been confirmed.
/// </remarks>
public event EventHandler<ustring> SelectedItemChanged;
public Action<ListViewItemEventArgs> SelectedItemChanged;
/// <summary>
/// This event is raised when the user Double Clicks on an item or presses ENTER to open the selected item.
/// </summary>
public Action<ListViewItemEventArgs> OpenSelectedItem;
IList searchset;
ustring text = "";
readonly TextField search;
readonly ListView listview;
int height;
int width;
bool autoHide = true;
/// <summary>
/// Public constructor
/// </summary>
public ComboBox () : base()
public ComboBox () : base ()
{
search = new TextField ("");
listview = new ListView () { LayoutStyle = LayoutStyle.Computed, CanFocus = true };
@@ -81,6 +81,19 @@ namespace Terminal.Gui {
Initialize ();
}
/// <summary>
/// Public constructor
/// </summary>
/// <param name="text"></param>
public ComboBox (ustring text) : base ()
{
search = new TextField ("");
listview = new ListView () { LayoutStyle = LayoutStyle.Computed, CanFocus = true };
Initialize ();
Text = text;
}
/// <summary>
/// Public constructor
/// </summary>
@@ -88,42 +101,45 @@ namespace Terminal.Gui {
/// <param name="source"></param>
public ComboBox (Rect rect, IList source) : base (rect)
{
SetSource (source);
this.height = rect.Height;
this.width = rect.Width;
search = new TextField ("") { Width = width };
listview = new ListView (rect, source) { LayoutStyle = LayoutStyle.Computed };
search = new TextField ("") { Width = rect.Width };
listview = new ListView (rect, source) { LayoutStyle = LayoutStyle.Computed, ColorScheme = Colors.Base };
Initialize ();
SetSource (source);
}
static IListDataSource MakeWrapper (IList source)
private void Initialize ()
{
return new ListWrapper (source);
}
private void Initialize()
{
ColorScheme = Colors.Base;
search.TextChanged += Search_Changed;
search.MouseClick += Search_MouseClick;
listview.Y = Pos.Bottom (search);
listview.OpenSelectedItem += (ListViewItemEventArgs a) => Selected ();
this.Add (listview, search);
this.SetFocus (search);
// On resize
LayoutComplete += (LayoutEventArgs a) => {
search.Width = Bounds.Width;
listview.Width = autoHide ? Bounds.Width - 1 : Bounds.Width;
if (!autoHide && search.Frame.Width != Bounds.Width ||
autoHide && search.Frame.Width != Bounds.Width - 1) {
search.Width = Bounds.Width;
listview.Width = listview.Width = autoHide ? Bounds.Width - 1 : Bounds.Width;
listview.Height = CalculatetHeight ();
search.SetRelativeLayout (Bounds);
listview.SetRelativeLayout (Bounds);
}
};
listview.SelectedItemChanged += (ListViewItemEventArgs e) => {
if(searchset.Count > 0)
SetValue ((ustring)searchset [listview.SelectedItem]);
if (searchset.Count > 0) {
SetValue (searchset [listview.SelectedItem]);
}
};
#if false
Application.Loaded += (Application.ResizedEventArgs a) => {
Added += (View v) => {
// Determine if this view is hosted inside a dialog
for (View view = this.SuperView; view != null; view = view.SuperView) {
if (view is Dialog) {
@@ -132,63 +148,60 @@ namespace Terminal.Gui {
}
}
ResetSearchSet ();
ColorScheme = autoHide ? Colors.Base : ColorScheme = null;
// Needs to be re-applied for LayoutStyle.Computed
// If Dim or Pos are null, these are the from the parametrized constructor
listview.Y = 1;
if (Width == null) {
listview.Width = CalculateWidth ();
search.Width = width;
} else {
width = GetDimAsInt (Width, vertical: false);
search.Width = width;
listview.Width = CalculateWidth ();
}
if (Height == null) {
var h = CalculatetHeight ();
listview.Height = h;
this.Height = h + 1; // adjust view to account for search box
} else {
if (height == 0)
height = GetDimAsInt (Height, vertical: true);
listview.Height = CalculatetHeight ();
this.Height = height + 1; // adjust view to account for search box
}
if (this.Text != null)
Search_Changed (Text);
if (autoHide)
listview.ColorScheme = Colors.Menu;
else
search.ColorScheme = Colors.Menu;
SetNeedsLayout ();
SetNeedsDisplay ();
Search_Changed (Text);
};
#endif
search.MouseClick += Search_MouseClick;
this.Add(listview, search);
this.SetFocus(search);
}
private void Search_MouseClick (MouseEventArgs e)
{
if (e.MouseEvent.Flags != MouseFlags.Button1Clicked)
return;
/// <summary>
/// Gets the index of the currently selected item in the <see cref="Source"/>
/// </summary>
/// <value>The selected item or -1 none selected.</value>
public int SelectedItem { private set; get; }
SuperView.SetFocus (search);
bool isShow = false;
///<inheritdoc/>
public new ColorScheme ColorScheme {
get {
return base.ColorScheme;
}
set {
listview.ColorScheme = value;
base.ColorScheme = value;
SetNeedsDisplay ();
}
}
private void Search_MouseClick (MouseEventArgs me)
{
if (me.MouseEvent.X == Bounds.Right - 1 && me.MouseEvent.Y == Bounds.Top && me.MouseEvent.Flags == MouseFlags.Button1Pressed
&& search.Text == "" && autoHide) {
if (isShow) {
HideList ();
isShow = false;
} else {
// force deep copy
foreach (var item in Source.ToList()) {
searchset.Add (item);
}
ShowList ();
isShow = true;
}
} else {
SuperView.SetFocus (search);
}
}
///<inheritdoc/>
public override bool OnEnter ()
public override bool OnEnter (View view)
{
if (!search.HasFocus)
if (!search.HasFocus) {
this.SetFocus (search);
}
search.CursorPosition = search.Text.RuneCount;
@@ -203,46 +216,64 @@ namespace Terminal.Gui {
{
// Note: Cannot rely on "listview.SelectedItem != lastSelectedItem" because the list is dynamic.
// So we cannot optimize. Ie: Don't call if not changed
SelectedItemChanged?.Invoke (this, search.Text);
SelectedItemChanged?.Invoke (new ListViewItemEventArgs(SelectedItem, search.Text));
return true;
}
/// <summary>
/// Invokes the OnOpenSelectedItem event if it is defined.
/// </summary>
/// <returns></returns>
public virtual bool OnOpenSelectedItem ()
{
var value = search.Text;
OpenSelectedItem?.Invoke (new ListViewItemEventArgs (SelectedItem, value));
return true;
}
///<inheritdoc/>
public override bool ProcessKey(KeyEvent e)
public override void Redraw (Rect bounds)
{
base.Redraw (bounds);
if (!autoHide) {
return;
}
Move (Bounds.Right - 1, 0);
Driver.AddRune (Driver.DownArrow);
}
///<inheritdoc/>
public override bool ProcessKey (KeyEvent e)
{
if (e.Key == Key.Tab) {
base.ProcessKey(e);
base.ProcessKey (e);
return false; // allow tab-out to next control
}
if(e.Key == Key.BackTab) {
base.ProcessKey (e);
this.FocusPrev ();
return false; // allow tab-out to prev control
}
if (e.Key == Key.Enter && listview.HasFocus) {
if (listview.Source.Count == 0 || searchset.Count == 0) {
text = "";
return true;
}
SetValue((ustring)searchset [listview.SelectedItem]);
search.CursorPosition = search.Text.RuneCount;
Search_Changed (search.Text);
OnSelectedChanged ();
searchset.Clear();
listview.Clear ();
listview.Height = 0;
this.SetFocus(search);
Selected ();
return true;
}
if (e.Key == Key.CursorDown && search.HasFocus && listview.SelectedItem == 0 && searchset.Count > 0) { // jump to list
if (e.Key == Key.CursorDown && search.HasFocus && searchset.Count > 0) { // jump to list
this.SetFocus (listview);
SetValue ((ustring)searchset [listview.SelectedItem]);
SetValue (searchset [listview.SelectedItem]);
return true;
}
if (e.Key == Key.CursorUp && search.HasFocus) // stop odd behavior on KeyUp when search has focus
if (e.Key == Key.CursorUp && search.HasFocus) { // stop odd behavior on KeyUp when search has focus
return true;
}
if (e.Key == Key.CursorUp && listview.HasFocus && listview.SelectedItem == 0 && searchset.Count > 0) // jump back to search
{
@@ -251,6 +282,34 @@ namespace Terminal.Gui {
return true;
}
if(e.Key == Key.PageDown) {
if (listview.SelectedItem != -1) {
listview.MovePageDown ();
}
return true;
}
if (e.Key == Key.PageUp) {
if (listview.SelectedItem != -1) {
listview.MovePageUp ();
}
return true;
}
if (e.Key == Key.Home) {
if (listview.SelectedItem != -1) {
listview.MoveHome ();
}
return true;
}
if(e.Key == Key.End) {
if(listview.SelectedItem != -1) {
listview.MoveEnd ();
}
return true;
}
if (e.Key == Key.Esc) {
this.SetFocus (search);
search.Text = text = "";
@@ -259,22 +318,19 @@ namespace Terminal.Gui {
}
// Unix emulation
if (e.Key == Key.ControlU)
{
Reset();
if (e.Key == Key.ControlU) {
Reset ();
return true;
}
return base.ProcessKey(e);
return base.ProcessKey (e);
}
/// <summary>
/// The currently selected list item
/// </summary>
public new ustring Text
{
get
{
public new ustring Text {
get {
return text;
}
set {
@@ -282,92 +338,131 @@ namespace Terminal.Gui {
}
}
private void SetValue(ustring text)
private void SetValue (object text)
{
search.TextChanged -= Search_Changed;
this.text = search.Text = text;
this.text = search.Text = text.ToString();
search.CursorPosition = 0;
search.TextChanged += Search_Changed;
SelectedItem = GetSelectedItemFromSource (this.text);
OnSelectedChanged ();
}
private void Selected ()
{
if (listview.Source.Count == 0 || searchset.Count == 0) {
text = "";
return;
}
SetValue (searchset [listview.SelectedItem]);
search.CursorPosition = search.Text.RuneCount;
Search_Changed (search.Text);
OnOpenSelectedItem ();
Reset (keepSearchText: true);
}
private int GetSelectedItemFromSource (ustring value)
{
if (source == null) {
return -1;
}
for (int i = 0; i < source.Count; i++) {
if (source.ToList () [i].ToString () == value) {
return i;
}
}
return -1;
}
/// <summary>
/// Reset to full original list
/// </summary>
private void Reset()
private void Reset (bool keepSearchText = false)
{
search.Text = text = "";
OnSelectedChanged();
if (!keepSearchText) {
search.Text = text = "";
}
ResetSearchSet ();
listview.SetSource(searchset);
listview.Height = CalculatetHeight ();
this.SetFocus(search);
}
private void ResetSearchSet()
{
if (autoHide) {
if (searchset == null)
searchset = new List<string> ();
else
searchset.Clear ();
} else
searchset = source.ToList ();
}
private void Search_Changed (ustring text)
{
if (source == null) // Object initialization
return;
if (ustring.IsNullOrEmpty (search.Text))
ResetSearchSet ();
else
searchset = source.ToList().Cast<ustring>().Where (x => x.StartsWith (search.Text)).ToList();
listview.SetSource (searchset);
listview.Height = CalculatetHeight ();
listview.Redraw (new Rect (0, 0, width, height)); // for any view behind this
this.SetFocus (search);
}
private void ResetSearchSet (bool noCopy = false)
{
if (searchset == null) {
searchset = new List<object> ();
} else {
searchset.Clear ();
}
if (autoHide || noCopy)
return;
// force deep copy
foreach (var item in Source.ToList ()) {
searchset.Add (item);
}
}
private void Search_Changed (ustring text)
{
if (source == null) { // Object initialization
return;
}
if (ustring.IsNullOrEmpty (search.Text)) {
ResetSearchSet ();
} else {
ResetSearchSet (noCopy: true);
foreach (var item in source.ToList ()) { // Iterate to preserver object type and force deep copy
if (item.ToString().StartsWith (search.Text.ToString(), StringComparison.CurrentCultureIgnoreCase)) {
searchset.Add (item);
}
}
}
ShowList ();
}
/// <summary>
/// Show the search list
/// </summary>
///
/// Consider making public
private void ShowList ()
{
listview.SetSource (searchset);
listview.Clear (); // Ensure list shrinks in Dialog as you type
listview.Height = CalculatetHeight ();
this.SuperView?.BringSubviewToFront (this);
}
/// <summary>
/// Hide the search list
/// </summary>
///
/// Consider making public
private void HideList ()
{
Reset ();
}
/// <summary>
/// Internal height of dynamic search list
/// </summary>
/// <returns></returns>
private int CalculatetHeight ()
{
return Math.Min (height, searchset.Count);
}
if (Bounds.Height == 0)
return 0;
/// <summary>
/// Internal width of search list
/// </summary>
/// <returns></returns>
private int CalculateWidth ()
{
return autoHide ? Math.Max (1, width - 1) : width;
}
/// <summary>
/// Get Dim as integer value
/// </summary>
/// <param name="dim"></param>
/// <param name="vertical"></param>
/// <returns></returns>n
private int GetDimAsInt (Dim dim, bool vertical)
{
if (dim is Dim.DimAbsolute)
return dim.Anchor (0);
else { // Dim.Fill Dim.Factor
if(autoHide)
return vertical ? dim.Anchor (SuperView.Bounds.Height) : dim.Anchor (SuperView.Bounds.Width);
else
return vertical ? dim.Anchor (Bounds.Height) : dim.Anchor (Bounds.Width);
}
return Math.Min (Bounds.Height - 1, searchset?.Count ?? 0);
}
}
}

View File

@@ -589,15 +589,17 @@ namespace Terminal.Gui {
/// <param name="source"></param>
public ListWrapper (IList source)
{
count = source.Count;
marks = new BitArray (count);
this.src = source;
if (source != null) {
count = source.Count;
marks = new BitArray (count);
this.src = source;
}
}
/// <summary>
/// Gets the number of items in the <see cref="IList"/>.
/// </summary>
public int Count => src.Count;
public int Count => src != null ? src.Count : 0;
void RenderUstr (ConsoleDriver driver, ustring ustr, int col, int line, int width)
{
@@ -632,7 +634,7 @@ namespace Terminal.Gui {
container.Move (col, line);
var t = src [item];
if (t == null) {
RenderUstr (driver, ustring.Make(""), col, line, width);
RenderUstr (driver, ustring.Make (""), col, line, width);
} else {
if (t is ustring) {
RenderUstr (driver, (ustring)t, col, line, width);

View File

@@ -535,8 +535,6 @@ namespace Terminal.Gui {
if (item == null || !item.IsEnabled ()) disabled = true;
if (item != null && !disabled)
current = me.Y - 1;
HasFocus = true;
SetNeedsDisplay ();
CheckSubMenu ();
return true;
}

View File

@@ -93,14 +93,14 @@ namespace Terminal.Gui {
}
///<inheritdoc/>
public override bool OnLeave ()
public override bool OnLeave (View view)
{
if (Application.mouseGrabView != null && Application.mouseGrabView == this)
Application.UngrabMouse ();
if (SelectedLength != 0 && !(Application.mouseGrabView is MenuBar))
ClearAllSelection ();
return base.OnLeave ();
return base.OnLeave (view);
}
///<inheritdoc/>

View File

@@ -372,7 +372,7 @@ namespace UICatalog {
// If the view supports a Source property, set it so we have something to look at
if (view != null && view.GetType ().GetProperty ("Source") != null && view.GetType().GetProperty("Source").PropertyType == typeof(Terminal.Gui.IListDataSource)) {
var source = new ListWrapper (new List<ustring> () { ustring.Make ("List Item #1"), ustring.Make ("List Item #2"), ustring.Make ("List Item #3")});
var source = new ListWrapper (new List<ustring> () { ustring.Make ("Test Text #1"), ustring.Make ("Test Text #2"), ustring.Make ("Test Text #3") });
view?.GetType ().GetProperty ("Source")?.GetSetMethod ()?.Invoke (view, new [] { source });
}

View File

@@ -12,13 +12,14 @@ namespace UICatalog.Scenarios {
public override void Setup ()
{
List<string> items = new List<string> ();
foreach (var dir in new [] { "/etc", @"\windows\System32" }) {
//TODO: Duplicated code in Demo.cs Consider moving to shared assembly
var items = new List<ustring> ();
foreach (var dir in new [] { "/etc", @$"{Environment.GetEnvironmentVariable ("SystemRoot")}\System32" }) {
if (Directory.Exists (dir)) {
items = Directory.GetFiles (dir).Union(Directory.GetDirectories(dir))
.Select (Path.GetFileName)
.Where (x => char.IsLetterOrDigit (x [0]))
.OrderBy (x => x).ToList ();
.Select (Path.GetFileName)
.Where (x => char.IsLetterOrDigit (x [0]))
.OrderBy (x => x).Select(x => ustring.Make(x)).ToList() ;
}
}
@@ -26,16 +27,16 @@ namespace UICatalog.Scenarios {
var lbListView = new Label ("Listview") {
ColorScheme = Colors.TopLevel,
X = 0,
Width = 30
Width = Dim.Percent (40)
};
var listview = new ListView (items) {
X = 0,
Y = Pos.Bottom (lbListView) + 1,
Height = Dim.Fill(2),
Width = 30
Width = Dim.Percent (40)
};
listview.OpenSelectedItem += (ListViewItemEventArgs e) => lbListView.Text = items [listview.SelectedItem];
listview.SelectedItemChanged += (ListViewItemEventArgs e) => lbListView.Text = items [listview.SelectedItem];
Win.Add (lbListView, listview);
// ComboBox
@@ -53,7 +54,7 @@ namespace UICatalog.Scenarios {
};
comboBox.SetSource (items);
comboBox.SelectedItemChanged += (object sender, ustring text) => lbComboBox.Text = text;
comboBox.SelectedItemChanged += (ListViewItemEventArgs text) => lbComboBox.Text = items[comboBox.SelectedItem];
Win.Add (lbComboBox, comboBox);
}
}

View File

@@ -32,8 +32,8 @@ namespace Terminal.Gui {
Assert.False (r.MouseEvent (new MouseEvent () { Flags = MouseFlags.AllEvents }));
Assert.False (r.OnMouseEnter (new MouseEvent () { Flags = MouseFlags.AllEvents }));
Assert.False (r.OnMouseLeave (new MouseEvent () { Flags = MouseFlags.AllEvents }));
Assert.False (r.OnEnter ());
Assert.False (r.OnLeave ());
Assert.False (r.OnEnter (new View ()));
Assert.False (r.OnLeave (new View ()));
}
}
}

View File

@@ -102,8 +102,8 @@ namespace Terminal.Gui {
Assert.False (r.MouseEvent (new MouseEvent () { Flags = MouseFlags.AllEvents }));
Assert.False (r.OnMouseEnter (new MouseEvent () { Flags = MouseFlags.AllEvents }));
Assert.False (r.OnMouseLeave (new MouseEvent () { Flags = MouseFlags.AllEvents }));
Assert.False (r.OnEnter ());
Assert.False (r.OnLeave ());
Assert.False (r.OnEnter (new View ()));
Assert.False (r.OnLeave (new View ()));
// TODO: Add more
}
@@ -135,5 +135,26 @@ namespace Terminal.Gui {
sub2.Width = Dim.Width (sub2);
Assert.Throws<InvalidOperationException> (() => root.LayoutSubviews ());
}
[Fact]
public void Added_Removing ()
{
var v = new View (new Rect (0, 0, 10, 24));
var t = new View ();
v.Added += (View e) => {
Assert.True (v.SuperView == e);
};
v.Removed += (View e) => {
Assert.True (v.SuperView == null);
};
t.Add (v);
Assert.True (t.Subviews.Count == 1);
t.Remove (v);
Assert.True (t.Subviews.Count == 0);
}
}
}