/// <summary> /// Writes a collection of item for selecting. /// </summary> /// <typeparam name="T">The type of data.</typeparam> /// <param name="cli">The command line interface proxy.</param> /// <param name="collection">The collection data.</param> /// <param name="options">The selection display options.</param> /// <param name="select">The index of item selected.</param> /// <returns>The result of selection.</returns> private static SelectionResult <T> Select <T>(StyleConsole cli, SelectionData <T> collection, SelectionConsoleOptions options, int select) { var temp = (0, 0, 0, 0, false, false, 0, 0); var oldSelect = select; while (true) { var list = collection.ToList(); void resetSelect() { if (oldSelect < 0 || oldSelect >= list.Count) { return; } var h = temp.Item3 + (temp.Item5 ? 2 : 1) + (temp.Item6 ? 1 : 0); var oldItem = list[oldSelect]; var y2 = Math.DivRem(oldSelect % temp.Item7, temp.Item4, out var x2) - h; x2 *= temp.Item8; cli.MoveCursorBy(x2, y2); RenderData(cli, oldItem, options, false, temp.Item8); cli.MoveCursorBy(-x2 - temp.Item8, -y2); }; if (temp.Item3 > 0 && select >= temp.Item1 && select < (temp.Item1 + temp.Item2)) { cli.BackspaceToBeginning(); var h = temp.Item3 + (temp.Item5 ? 2 : 1) + (temp.Item6 ? 1 : 0); if (oldSelect != select) { resetSelect(); } if (select < 0 || select >= list.Count) { select = 0; } var item = list[select]; var y = Math.DivRem(select % temp.Item7, temp.Item4, out var x) - h; x *= temp.Item8; cli.MoveCursorBy(x, y); RenderData(cli, item, options, true, temp.Item8); cli.MoveCursorBy(-x - temp.Item8, -y); RenderSelectResult(cli, item?.Title, options); } else { if (temp.Item3 > 0) { cli.BackspaceToBeginning(); var h = temp.Item3 + (temp.Item5 ? 2 : 1) + (temp.Item6 ? 1 : 0); for (var i = 0; i < h; i++) { cli.MoveCursorBy(0, -1); cli.Clear(StyleConsole.RelativeAreas.Line); } } temp = RenderData(cli, list, options, select); } oldSelect = select; ConsoleKeyInfo key; try { key = cli.ReadKey(); } catch (InvalidOperationException) { return(SelectByManualTyping(cli, collection, options)); } catch (IOException) { return(SelectByManualTyping(cli, collection, options)); } catch (SecurityException) { return(SelectByManualTyping(cli, collection, options)); } catch (NotSupportedException) { return(SelectByManualTyping(cli, collection, options)); } switch (key.Key) { case ConsoleKey.Enter: case ConsoleKey.Select: case ConsoleKey.Spacebar: if (select < 0 || select >= list.Count) { select = temp.Item1; if (select < 0 || select >= list.Count) { select = 0; } break; } var sel = list[select]; RenderSelectResult(cli, sel?.Title, options); cli.WriteLine(); return(new SelectionResult <T>(sel.Title, select, sel.Data, sel.Title)); case ConsoleKey.Backspace: case ConsoleKey.Delete: case ConsoleKey.Clear: cli.WriteImmediately(' '); cli.BackspaceToBeginning(); resetSelect(); return(SelectByManualTyping(cli, collection, options)); case ConsoleKey.Escape: case ConsoleKey.Pause: cli.WriteImmediately(' '); cli.BackspaceToBeginning(); resetSelect(); RenderSelectResult(cli, null, options); cli.WriteLine(); return(new SelectionResult <T>(string.Empty, SelectionResultTypes.Canceled)); case ConsoleKey.Help: case ConsoleKey.F1: { cli.BackspaceToBeginning(); resetSelect(); RenderSelectResult(cli, "?", options); cli.WriteLine(); var item = collection.Get('?', out select); return(item == null ? new SelectionResult <T>("?", SelectionResultTypes.Selected) : new SelectionResult <T>("?", select, item.Data, item.Title)); } case ConsoleKey.F4: if (temp.Item3 > 0) { cli.BackspaceToBeginning(); var h = temp.Item3 + (temp.Item5 ? 2 : 1) + (temp.Item6 ? 1 : 0); for (var i = 0; i < h; i++) { cli.MoveCursorBy(0, -1); cli.Clear(StyleConsole.RelativeAreas.Line); } } return(SelectByManualTyping(cli, collection, options, true)); case ConsoleKey.F5: if (key.Modifiers.HasFlag(ConsoleModifiers.Control)) { select = 0; } break; case ConsoleKey.F6: cli.BackspaceToBeginning(); resetSelect(); RenderSelectResult(cli, null, options); cli.WriteLine(); if (key.Modifiers.HasFlag(ConsoleModifiers.Control)) { select = 0; } temp = RenderData(cli, list, options, select); break; case ConsoleKey.F12: { cli.BackspaceToBeginning(); resetSelect(); RenderSelectResult(cli, "?", options); cli.WriteLine(); var item = collection.Get('?', out select); return(item == null ? new SelectionResult <T>("?", SelectionResultTypes.Canceled) : new SelectionResult <T>("?", select, item.Data, item.Title)); } case ConsoleKey.PageUp: if (key.Modifiers.HasFlag(ConsoleModifiers.Control)) { select = 0; } else { select = Math.Max(0, temp.Item1 - temp.Item7); } break; case ConsoleKey.PageDown: if (key.Modifiers.HasFlag(ConsoleModifiers.Control)) { select = list.Count - 1; } else { select = Math.Min(list.Count - 1, temp.Item1 + temp.Item7); } break; case ConsoleKey.UpArrow: if (select < temp.Item4) { select += list.Count - (list.Count % temp.Item4); if (select >= list.Count) { select -= temp.Item4; } if (select >= list.Count) { select = list.Count - 1; } else if (select < 0) { select = 0; } } else { select -= temp.Item4; } break; case ConsoleKey.DownArrow: select += temp.Item4; if (select >= list.Count) { select %= temp.Item4; if (select >= list.Count) { select = list.Count - 1; } } break; case ConsoleKey.LeftArrow: select--; if (select < 0) { select = list.Count - 1; } break; case ConsoleKey.RightArrow: select++; if (select >= list.Count) { select = 0; } break; case ConsoleKey.Home: if (key.Modifiers.HasFlag(ConsoleModifiers.Control)) { select = 0; } else { select = temp.Item1; } break; case ConsoleKey.End: if (key.Modifiers.HasFlag(ConsoleModifiers.Control)) { select = list.Count - 1; } else { select = temp.Item1 + temp.Item2 - 1; } break; default: { var item = collection.Get(key.KeyChar, out select); if (item == null) { select = oldSelect; continue; } cli.WriteImmediately(' '); cli.BackspaceToBeginning(); resetSelect(); RenderSelectResult(cli, item.Title, options); cli.WriteLine(); return(new SelectionResult <T>(item.Title, select, item.Data, item.Title)); } } } }