Merge branch 'master' of tig:migueldeicaza/gui.cs

This commit is contained in:
Charlie Kindel
2020-05-12 10:39:38 -06:00
22 changed files with 2148 additions and 2110 deletions

View File

@@ -6,6 +6,7 @@ csharp_new_line_before_open_brace = methods,local_functions
csharp_new_line_before_else = false
csharp_new_line_before_catch = false
csharp_new_line_before_finally = false
end_of_line = crlf
csharp_indent_case_contents = true
csharp_indent_switch_labels = false

13
.gitattributes vendored Normal file
View File

@@ -0,0 +1,13 @@
# Set the default behavior for all files.
* text=auto
# Normalized and converts to
# native line endings on checkout.
*.cs text
# Convert to LF line endings on checkout.
*.sh text eol=lf
# Binary files.
*.png binary
*.jpg binary

5
.gitignore vendored
View File

@@ -1,8 +1,9 @@
bin
obj
*~
~$*
*.userprefs
*~
packages
.vs
*.csproj.user
# User-specific files
*.user

View File

@@ -6,6 +6,7 @@ using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using NStack;
using System.Text;
static class Demo {
//class Box10x : View, IScrollView {
@@ -81,22 +82,26 @@ static class Demo {
}
}
static void ShowTextAlignments ()
{
var container = new Dialog (
"Text Alignments", 50, 20,
new Button ("Ok", is_default: true) { Clicked = () => { Application.RequestStop (); } },
new Button ("Cancel") { Clicked = () => { Application.RequestStop (); } });
var container = new Window ($"Show Text Alignments") {
X = 0,
Y = 0,
Width = Dim.Fill (),
Height = Dim.Fill ()
};
container.OnKeyUp += (KeyEvent ke) => {
if (ke.Key == Key.Esc)
container.Running = false;
};
int i = 0;
string txt = "Hello world, how are you doing today";
string txt = "Hello world, how are you doing today?";
container.Add (
new Label(new Rect(0, 1, 40, 3), $"{i+1}-{txt}") { TextAlignment = TextAlignment.Left },
new Label(new Rect(0, 3, 40, 3), $"{i+2}-{txt}") { TextAlignment = TextAlignment.Right },
new Label(new Rect(0, 5, 40, 3), $"{i+3}-{txt}") { TextAlignment = TextAlignment.Centered },
new Label(new Rect(0, 7, 40, 3), $"{i+4}-{txt}") { TextAlignment = TextAlignment.Justified }
new Label ($"{i+1}-{txt}") { TextAlignment = TextAlignment.Left, Y = 3, Width = Dim.Fill () },
new Label ($"{i+2}-{txt}") { TextAlignment = TextAlignment.Right, Y = 5, Width = Dim.Fill () },
new Label ($"{i+3}-{txt}") { TextAlignment = TextAlignment.Centered, Y = 7, Width = Dim.Fill () },
new Label ($"{i+4}-{txt}") { TextAlignment = TextAlignment.Justified, Y = 9, Width = Dim.Fill () }
);
Application.Run (container);
@@ -408,6 +413,44 @@ static class Demo {
#endregion
#region OnKeyDown / OnKeyUp Demo
private static void OnKeyDownUpDemo ()
{
var container = new Dialog (
"OnKeyDown & OnKeyUp demo", 80, 20,
new Button ("Close") { Clicked = () => { Application.RequestStop (); } }) {
Width = Dim.Fill (),
Height = Dim.Fill (),
};
var list = new List<string> ();
var listView = new ListView (list) {
X = 0,
Y = 0,
Width = Dim.Fill () - 1,
Height = Dim.Fill () - 2,
};
listView.ColorScheme = Colors.TopLevel;
container.Add (listView);
void KeyUpDown (KeyEvent keyEvent, string updown)
{
if ((keyEvent.Key & Key.CtrlMask) != 0) {
list.Add ($"Key{updown,-4}: Ctrl ");
} else if ((keyEvent.Key & Key.AltMask) != 0) {
list.Add ($"Key{updown,-4}: Alt ");
} else {
list.Add ($"Key{updown,-4}: {(((uint)keyEvent.KeyValue & (uint)Key.CharMask) > 26 ? $"{(char)keyEvent.KeyValue}" : $"{keyEvent.Key}")}");
}
listView.MoveDown ();
}
container.OnKeyDown += (KeyEvent keyEvent) => KeyUpDown (keyEvent, "Down");
container.OnKeyUp += (KeyEvent keyEvent) => KeyUpDown (keyEvent, "Up");
Application.Run (container);
}
#endregion
public static Label ml;
public static MenuBar menu;
public static CheckBox menuKeysStyle;
@@ -418,7 +461,6 @@ static class Demo {
CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.GetCultureInfo ("en-US");
//Application.UseSystemConsole = true;
Console.WindowHeight = 35;
Application.Init ();
@@ -426,11 +468,13 @@ static class Demo {
//Open ();
#if true
int margin = 3;
var win = new Window ("Hello") {
X = 1,
Y = 1,
Width = Dim.Fill (),
Height = Dim.Fill ()-1
Width = Dim.Fill () - margin,
Height = Dim.Fill () - margin
};
#else
var tframe = top.Frame;
@@ -451,7 +495,7 @@ static class Demo {
menu = new MenuBar (new MenuBarItem [] {
new MenuBarItem ("_File", new MenuItem [] {
new MenuItem ("Text Editor Demo", "", () => { Editor (top); }),
new MenuItem ("Text _Editor Demo", "", () => { Editor (top); }),
new MenuItem ("_New", "Creates new file", NewFile),
new MenuItem ("_Open", "", Open),
new MenuItem ("_Hex", "", () => ShowHex (top)),
@@ -469,18 +513,19 @@ static class Demo {
menuItems[3]
}),
new MenuBarItem ("_List Demos", new MenuItem [] {
new MenuItem ("Select Multiple Items", "", () => ListSelectionDemo (true)),
new MenuItem ("Select Single Item", "", () => ListSelectionDemo (false)),
new MenuItem ("Select _Multiple Items", "", () => ListSelectionDemo (true)),
new MenuItem ("Select _Single Item", "", () => ListSelectionDemo (false)),
}),
new MenuBarItem ("Assorted", new MenuItem [] {
new MenuItem ("Show text alignments", "", () => ShowTextAlignments ())
new MenuBarItem ("A_ssorted", new MenuItem [] {
new MenuItem ("_Show text alignments", "", () => ShowTextAlignments ()),
new MenuItem ("_OnKeyDown/Up", "", () => OnKeyDownUpDemo ())
}),
new MenuBarItem ("Test Menu and SubMenus", new MenuItem [] {
new MenuItem ("SubMenu1Item1",
new MenuBarItem ("_Test Menu and SubMenus", new MenuItem [] {
new MenuItem ("SubMenu1Item_1",
new MenuBarItem (new MenuItem[] {
new MenuItem ("SubMenu2Item1",
new MenuItem ("SubMenu2Item_1",
new MenuBarItem (new MenuItem [] {
new MenuItem ("SubMenu3Item1",
new MenuItem ("SubMenu3Item_1",
new MenuBarItem (new MenuItem [] { menuItems [2] })
)
})
@@ -488,6 +533,7 @@ static class Demo {
})
)
}),
new MenuBarItem ("_About...", "Demonstrates top-level menu item", () => MessageBox.ErrorQuery (50, 7, "About Demo", "This is a demo app for gui.cs", "Ok")),
});
menuKeysStyle = new CheckBox (3, 25, "UseKeysUpDownAsKeysLeftRight", true);
@@ -498,7 +544,7 @@ static class Demo {
ShowEntries (win);
int count = 0;
ml = new Label (new Rect (3, 18, 47, 1), "Mouse: ");
ml = new Label (new Rect (3, 17, 47, 1), "Mouse: ");
Application.RootMouseEvent += delegate (MouseEvent me) {
ml.TextColor = Colors.TopLevel.Normal;
ml.Text = $"Mouse: ({me.X},{me.Y}) - {me.Flags} {count++}";
@@ -520,24 +566,31 @@ static class Demo {
new StatusItem(Key.F2, "~F2~ Load", null),
new StatusItem(Key.F3, "~F3~ Save", null),
new StatusItem(Key.ControlX, "~^X~ Quit", () => { if (Quit ()) top.Running = false; }),
});
}) {
Parent = null,
};
win.Add (drag, dragText);
#if true
// This currently causes a stack overflow, because it is referencing a window that has not had its size allocated yet
// FIXED: This currently causes a stack overflow, because it is referencing a window that has not had its size allocated yet
var bottom = new Label ("This should go on the bottom!");
var bottom = new Label ("This should go on the bottom of the same top-level!");
win.Add (bottom);
var bottom2 = new Label ("This should go on the bottom of another top-level!");
top.Add (bottom2);
Application.OnResized = () => {
bottom.X = Pos.Left (win);
bottom.Y = Pos.Bottom (win);
Application.OnLoad = () => {
bottom.X = win.X;
bottom.Y = Pos.Bottom (win) - Pos.Top (win) - margin;
bottom2.X = Pos.Left (win);
bottom2.Y = Pos.Bottom (win);
};
#endif
top.Add (win);
//top.Add (menu);
top.Add (menu, statusBar, ml);
top.Add (menu, statusBar);
Application.Run ();
}
}

View File

@@ -0,0 +1,4 @@
[*.fs]
indent_style = space
indent_size = 4
tab_width = 4

View File

@@ -10,7 +10,11 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Terminal.Gui" Version="0.9.0" />
<ProjectReference Include="..\Terminal.Gui\Terminal.Gui.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Update="FSharp.Core" Version="4.7.1" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30011.22
MinimumVisualStudioVersion = 10.0.40219.1
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharpExample", "FSharpExample.fsproj", "{6E4DF691-FA5F-4D7C-8DBC-8656103C5CB1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Terminal.Gui", "..\Terminal.Gui\Terminal.Gui.csproj", "{FA48E777-1308-489D-95A0-89DE46B65A93}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{6E4DF691-FA5F-4D7C-8DBC-8656103C5CB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6E4DF691-FA5F-4D7C-8DBC-8656103C5CB1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6E4DF691-FA5F-4D7C-8DBC-8656103C5CB1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6E4DF691-FA5F-4D7C-8DBC-8656103C5CB1}.Release|Any CPU.Build.0 = Release|Any CPU
{FA48E777-1308-489D-95A0-89DE46B65A93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FA48E777-1308-489D-95A0-89DE46B65A93}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FA48E777-1308-489D-95A0-89DE46B65A93}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FA48E777-1308-489D-95A0-89DE46B65A93}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A023D2E3-EF0F-4986-8E6C-323F967788B7}
EndGlobalSection
EndGlobal

View File

@@ -1,37 +1,441 @@
// Learn more about F# at http://fsharp.org
open System
open Terminal.Gui
open System
open Mono.Terminal
open System.Collections.Generic
open System.Diagnostics
open System.Globalization
open System.Reflection
open NStack
type Demo() = class end
let ustr (x:string) = ustring.Make(x)
let mutable ml2 = Unchecked.defaultof<Label>
let mutable ml = Unchecked.defaultof<Label>
let mutable menu = Unchecked.defaultof<MenuBar>
let mutable menuKeysStyle = Unchecked.defaultof<CheckBox>
let mutable menuAutoMouseNav = Unchecked.defaultof<CheckBox>
let ustr (x:string) = ustring.Make(x)
type Box10x() =
inherit View()
member val w = 40 with get, set
member val h = 50 with get, set
member val WantCursorPosition = Unchecked.defaultof<System.Boolean> with get, set
new(x : int, y : int) as this =
(Box10x())
then
()
member this.GetContentSize() =
new Size(this.w, this.h)
member this.SetCursorPosition(pos : Point) =
raise (new NotImplementedException())
override this.Redraw(region : Rect) =
Application.Driver.SetAttribute (Application.Current.ColorScheme.Focus)
do
let mutable (y : int) = 0
while (y < this.h) do
this.Move (0, y)
Application.Driver.AddStr (ustr (y.ToString()))
do
let mutable (x : int) = 0
while (x < this.w - (y.ToString ()).Length) do
if (y.ToString ()).Length < this.w
then Application.Driver.AddStr (ustr " ")
x <- x + 1
x
y <- y + 1
y
()
let stop = Action Application.RequestStop
type Filler() =
inherit View()
new(rect : Rect) as this =
(Filler ())
then
()
override this.Redraw(region : Rect) =
Application.Driver.SetAttribute (Application.Current.ColorScheme.Focus)
let mutable f = this.Frame
do
let mutable (y : int) = 0
while (y < f.Width) do
this.Move (0, y)
do
let mutable (x : int) = 0
while (x < f.Height) do
let mutable (r : Rune) = Unchecked.defaultof<Rune>
match (x % 3) with
| 0 ->
Application.Driver.AddRune ((Rune ((y.ToString ()).ToCharArray (0, 1)).[0]))
if y > 9
then Application.Driver.AddRune ((Rune ((y.ToString ()).ToCharArray (1, 1)).[0]))
r <- (Rune '.')
| 1 ->
r <- (Rune 'o')
| _ ->
r <- (Rune 'O')
Application.Driver.AddRune (r)
x <- x + 1
x
y <- y + 1
y
()
let newFile() =
let ok = Button (ustr "Ok", true, Clicked=stop)
let cancel = Button (ustr "Cancel", Clicked=stop)
let d = Dialog (ustr ("New File"), 50, 20, ok, cancel)
Application.Run (d)
let ShowTextAlignments() =
let mutable container = new Dialog(
ustr "Text Alignments", 50, 20,
new Button (ustr "Ok", true, Clicked = Action(Application.RequestStop)),
new Button (ustr "Cancel", true, Clicked = Action(Application.RequestStop))
)
let mutable (i : int) = 0
let mutable (txt : string) = "Hello world, how are you doing today"
container.Add (
new Label (new Rect (0, 1, 40, 3), ustr ((sprintf "%O-%O" (i + 1)) txt), TextAlignment = TextAlignment.Left),
new Label (new Rect (0, 3, 40, 3), ustr ((sprintf "%O-%O" (i + 2)) txt), TextAlignment = TextAlignment.Right),
new Label (new Rect (0, 5, 40, 3), ustr ((sprintf "%O-%O" (i + 3)) txt), TextAlignment = TextAlignment.Centered),
new Label (new Rect (0, 7, 40, 3), ustr ((sprintf "%O-%O" (i + 4)) txt), TextAlignment = TextAlignment.Justified)
)
Application.Run (container)
let quit() =
if MessageBox.Query (50, 7, "Quit demo", "Are you sure you want to quit the demo?", "Yes", "No") = 0 then
Application.Top.Running <- false
let ShowEntries(container : View) =
let mutable scrollView = new ScrollView (new Rect (50, 10, 20, 8),
ContentSize = new Size (20, 50),
ShowVerticalScrollIndicator = true,
ShowHorizontalScrollIndicator = true
)
scrollView.Add (new Filler(new Rect(0, 0, 40, 40)))
let mutable scrollView2 = new ScrollView (new Rect (72, 10, 3, 3),
ContentSize = new Size (100, 100),
ShowVerticalScrollIndicator = true,
ShowHorizontalScrollIndicator = true
)
scrollView2.Add (new Box10x(0, 0))
let mutable progress = new ProgressBar(new Rect(68, 1, 10, 1))
let timer = Func<MainLoop, bool> (fun (caller) ->
progress.Pulse ();
true)
let buildMenu() =
MenuBar ([|
MenuBarItem (ustr ("File"),
[| MenuItem(ustr("_New"), "Creates a new file", System.Action newFile);
MenuItem(ustr("_Quit"), null, System.Action quit)
|])|])
Application.MainLoop.AddTimeout (TimeSpan.FromMilliseconds (300.0), timer) |> ignore
[<EntryPoint>]
let main argv =
Application.Init ()
let top = Application.Top
let win = Window (ustr "Hello", X=Pos.op_Implicit(0), Y=Pos.op_Implicit(1), Width=Dim.Fill(), Height=Dim.Fill())
top.Add (buildMenu())
top.Add (win)
Application.Run ()
0 // return an integer exit code
let mutable login = Label (ustr "Login: ",
X = Pos.At(3),
Y = Pos.At(6)
)
let mutable password = new Label (ustr "Password: ",
X = Pos.Left (login),
Y = Pos.Bottom (login) + Pos.At(1)
)
let mutable loginText = new TextField (ustr "",
X = Pos.Right (password),
Y = Pos.Top (login),
Width = Dim.op_Implicit(40)
)
let mutable passText = new TextField (ustr "",
Secret = true,
X = Pos.Left (loginText),
Y = Pos.Top (password),
Width = Dim.Width (loginText)
)
let mutable tf = new Button(3, 19, ustr "Ok")
container.Add (login, loginText, password, passText,
new FrameView (new Rect (3, 10, 25, 6), ustr "Options",
[|new CheckBox (1, 0, ustr "Remember me");
new RadioGroup (1, 2, [|"_Personal"; "_Company"|])|]
),
new ListView (new Rect(59, 6, 16, 4),
[|"First row";
"<>";
"This is a very long row that should overflow what is shown";
"4th";
"There is an empty slot on the second row";
"Whoa";
"This is so cool"|]
),
scrollView, scrollView2, tf,
new Button(10, 19, ustr "Cancel"),
new TimeField(3, 20, DateTime.Now),
new TimeField(23, 20, DateTime.Now, true),
new DateField(3, 22, DateTime.Now),
new DateField(23, 22, DateTime.Now, true),
progress,
new Label(3, 24, ustr "Press F9 (on Unix, ESC+9 is an alias) to activate the menubar"),
menuKeysStyle,
menuAutoMouseNav
)
container.SendSubviewToBack (tf)
()
let NewFile() =
let mutable d = new Dialog (ustr "New File", 50, 20,
new Button (ustr "Ok", true, Clicked = Action(Application.RequestStop)),
new Button (ustr "Cancel", true, Clicked = Action(Application.RequestStop))
)
ml2 <- new Label(1, 1, ustr "Mouse Debug Line")
d.Add (ml2)
Application.Run (d)
let Editor(top : Toplevel) =
let mutable tframe = top.Frame
let mutable ntop = new Toplevel(tframe)
let mutable menu = new MenuBar([|new MenuBarItem(ustr "_File",
[|new MenuItem(ustr "_Close", "", (fun () -> Application.RequestStop ()))|]);
new MenuBarItem(ustr "_Edit", [|new MenuItem(ustr "_Copy", "", Unchecked.defaultof<_>);
new MenuItem(ustr "C_ut", "", Unchecked.defaultof<_>);
new MenuItem(ustr "_Paste", "", Unchecked.defaultof<_>)|])|]
)
ntop.Add (menu)
let mutable (fname : string) = Unchecked.defaultof<_>
for s in [|"/etc/passwd"; "c:\\windows\\win.ini"|] do
if System.IO.File.Exists (s)
then
fname <- s
let mutable win = new Window (ustr(if fname <> null then fname else "Untitled"),
X = Pos.At(0),
Y = Pos.At(1),
Width = Dim.Fill (),
Height = Dim.Fill ()
)
ntop.Add (win)
let mutable text = new TextView(new Rect(0, 0, (tframe.Width - 2), (tframe.Height - 3)))
if fname <> Unchecked.defaultof<_>
then text.Text <- ustr (System.IO.File.ReadAllText (fname))
win.Add (text)
Application.Run (ntop)
let Quit() =
let mutable n = MessageBox.Query (50, 7, "Quit Demo", "Are you sure you want to quit this demo?", "Yes", "No")
n = 0
let Close() =
MessageBox.ErrorQuery (50, 7, "Error", "There is nothing to close", "Ok")
|> ignore
let Open() =
let mutable d = new OpenDialog (ustr "Open", ustr "Open a file", AllowsMultipleSelection = true)
Application.Run (d)
if not d.Canceled
then MessageBox.Query (50, 7, "Selected File", (String.Join (", ", d.FilePaths)), "Ok") |> ignore
let ShowHex(top : Toplevel) =
let mutable tframe = top.Frame
let mutable ntop = new Toplevel(tframe)
let mutable menu = new MenuBar([|new MenuBarItem(ustr "_File",
[|new MenuItem(ustr "_Close", "", (fun () -> Application.RequestStop ()))|])|])
ntop.Add (menu)
let mutable win = new Window (ustr "/etc/passwd",
X = Pos.At(0),
Y = Pos.At(1),
Width = Dim.Fill (),
Height = Dim.Fill ()
)
ntop.Add (win)
let mutable source = System.IO.File.OpenRead ("/etc/passwd")
let mutable hex = new HexView (source,
X = Pos.At(0),
Y = Pos.At(0),
Width = Dim.Fill (),
Height = Dim.Fill ()
)
win.Add (hex)
Application.Run (ntop)
type MenuItemDetails() =
inherit MenuItem()
new(title : ustring, help : string, action : Action) as this =
(MenuItemDetails ())
then
this.Title <- title
this.Help <- ustr help
this.Action <- action
static member Instance(mi : MenuItem) =
(mi.GetMenuItem ()) :?> MenuItemDetails
type MenuItemDelegate = delegate of MenuItemDetails -> MenuItem
let ShowMenuItem(mi : MenuItemDetails) =
let mutable (flags : BindingFlags) = BindingFlags.Public ||| BindingFlags.Static
let mutable (minfo : MethodInfo) = typeof<MenuItemDetails>.GetMethod ("Instance", flags)
let mutable (mid : Delegate) = Delegate.CreateDelegate (typeof<MenuItemDelegate>, minfo)
MessageBox.Query (70, 7, (mi.Title.ToString ()),
((sprintf "%O selected. Is from submenu: %O" (mi.Title.ToString ())) (mi.GetMenuBarItem ())), "Ok")
|> ignore
let MenuKeysStyle_Toggled(e : EventArgs) =
menu.UseKeysUpDownAsKeysLeftRight <- menuKeysStyle.Checked
let MenuAutoMouseNav_Toggled(e : EventArgs) =
menu.WantMousePositionReports <- menuAutoMouseNav.Checked
let Copy() =
let mutable (textField : TextField) = menu.LastFocused :?> TextField
if textField <> Unchecked.defaultof<_> && textField.SelectedLength <> 0
then textField.Copy ()
()
let Cut() =
let mutable (textField : TextField) = menu.LastFocused :?> TextField
if textField <> Unchecked.defaultof<_> && textField.SelectedLength <> 0
then textField.Cut ()
()
let Paste() =
let mutable (textField : TextField) = menu.LastFocused :?> TextField
if textField <> Unchecked.defaultof<_>
then textField.Paste ()
()
let Help() =
MessageBox.Query (50, 7, "Help", "This is a small help\nBe kind.", "Ok")
|> ignore
let ListSelectionDemo(multiple : System.Boolean) =
let mutable d = new Dialog (ustr "Selection Demo", 60, 20,
new Button (ustr "Ok", true, Clicked = fun () -> Application.RequestStop ()),
new Button (ustr "Cancel", Clicked = fun () -> Application.RequestStop ())
)
let mutable animals = new List<string> ()
animals.AddRange([|"Alpaca"; "Llama"; "Lion"; "Shark"; "Goat"|])
let mutable msg = new Label (ustr "Use space bar or control-t to toggle selection",
X = Pos.At(1),
Y = Pos.At(1),
Width = Dim.Fill () - Dim.op_Implicit(1),
Height = Dim.op_Implicit(1)
)
let mutable list = new ListView (animals,
X = Pos.At(1),
Y = Pos.At(3),
Width = Dim.Fill () - Dim.op_Implicit(4),
Height = Dim.Fill () - Dim.op_Implicit(4),
AllowsMarking = true,
AllowsMultipleSelection = multiple
)
d.Add (msg, list)
Application.Run (d)
let mutable result = ""
do
let mutable (i : int) = 0
while (i < animals.Count) do
if list.Source.IsMarked (i)
then result <- result + animals.[i] + " "
i <- i + 1
i
()
MessageBox.Query (60, 10, "Selected Animals", (if result = "" then "No animals selected" else result), "Ok") |> ignore
let KeyUpDown(keyEvent : KeyEvent, kl : Label, updown : string) =
kl.TextColor <- Colors.TopLevel.Normal
if keyEvent.Key &&& Key.CtrlMask <> Key.Unknown
then kl.Text <- ustr (sprintf "Keyboard: Ctrl Key%O" updown)
else
if keyEvent.Key &&& Key.AltMask <> Key.Unknown
then kl.Text <- ustr (sprintf "Keyboard: Alt Key%O" updown)
else kl.Text <- ustr (sprintf "Keyboard: %O Key%O" (char keyEvent.KeyValue) updown)
let OnKeyDownUpDemo() =
let mutable container = new Dialog(ustr "OnKeyDown & OnKeyUp demo", 50, 20,
new Button (ustr "Ok", true, Clicked = fun () -> Application.RequestStop ()),
new Button (ustr "Cancel", Clicked = fun () -> Application.RequestStop ())
)
let mutable kl = new Label(new Rect(3, 3, 40, 1), ustr "Keyboard: ")
container.OnKeyDown <- Action<KeyEvent>(fun (keyEvent : KeyEvent) -> KeyUpDown (keyEvent, kl, "Down"))
container.OnKeyUp <- Action<KeyEvent>(fun (keyEvent : KeyEvent) -> KeyUpDown (keyEvent, kl, "Up"))
container.Add (kl)
Application.Run (container)
let Main() =
if Debugger.IsAttached
then CultureInfo.DefaultThreadCurrentUICulture <- CultureInfo.GetCultureInfo ("en-US")
Application.Init ()
let mutable top = Application.Top
let mutable (margin : int) = 3
let mutable win = new Window (ustr "Hello",
X = Pos.At(1),
Y = Pos.At(1),
Width = Dim.Fill () - Dim.op_Implicit(margin),
Height = Dim.Fill () - Dim.op_Implicit(margin)
)
let mutable (menuItems : MenuItemDetails[]) = [|new MenuItemDetails(ustr "F_ind", "", Unchecked.defaultof<_>);
new MenuItemDetails(ustr "_Replace", "", Unchecked.defaultof<_>);
new MenuItemDetails(ustr "_Item1", "", Unchecked.defaultof<_>);
new MenuItemDetails(ustr "_Not From Sub Menu", "", Unchecked.defaultof<_>)|]
menuItems.[0].Action <- fun () -> ShowMenuItem (menuItems.[0])
menuItems.[1].Action <- fun () -> ShowMenuItem (menuItems.[1])
menuItems.[2].Action <- fun () -> ShowMenuItem (menuItems.[2])
menuItems.[3].Action <- fun () -> ShowMenuItem (menuItems.[3])
menu <-
new MenuBar ([|new MenuBarItem(ustr "_File",
[|new MenuItem (ustr "Text _Editor Demo", "", (fun () -> Editor (top)));
new MenuItem (ustr "_New", "Creates new file", fun () -> NewFile());
new MenuItem (ustr "_Open", "", fun () -> Open());
new MenuItem (ustr "_Hex", "", (fun () -> ShowHex (top)));
new MenuItem (ustr "_Close", "", (fun () -> Close()));
new MenuItem (ustr "_Disabled", "", (fun () -> ()), (fun () -> false));
Unchecked.defaultof<_>;
new MenuItem (ustr "_Quit", "", (fun () -> if Quit() then top.Running <- false))|]);
new MenuBarItem (ustr "_Edit", [|new MenuItem(ustr "_Copy", "", fun () -> Copy());
new MenuItem(ustr "C_ut", "", fun () -> Cut()); new MenuItem(ustr "_Paste", "", fun () -> Paste());
new MenuItem(ustr "_Find and Replace", new MenuBarItem([|(menuItems.[0]);
(menuItems.[1])|])); (menuItems.[3])|]);
new MenuBarItem(ustr "_List Demos", [|new MenuItem(ustr "Select _Multiple Items", "", (fun () -> ListSelectionDemo (true)));
new MenuItem(ustr "Select _Single Item", "", (fun () -> ListSelectionDemo (false)))|]);
new MenuBarItem(ustr "A_ssorted", [|new MenuItem(ustr "_Show text alignments", "", (fun () -> ShowTextAlignments ()));
new MenuItem(ustr "_OnKeyDown/Up", "", (fun () -> OnKeyDownUpDemo ()))|]);
new MenuBarItem(ustr "_Test Menu and SubMenus",
[|new MenuItem(ustr "SubMenu1Item_1", new MenuBarItem([|new MenuItem(ustr "SubMenu2Item_1",
new MenuBarItem([|new MenuItem(ustr "SubMenu3Item_1", new MenuBarItem([|(menuItems.[2])|]))|]))|]))|]);
new MenuBarItem(ustr "_About...", "Demonstrates top-level menu item",
(fun () -> MessageBox.ErrorQuery (50, 7, "About Demo", "This is a demo app for gui.cs", "Ok") |> ignore))|])
menuKeysStyle <- new CheckBox(3, 25, ustr "UseKeysUpDownAsKeysLeftRight", true)
menuKeysStyle.Toggled.Add(MenuKeysStyle_Toggled)
menuAutoMouseNav <- new CheckBox(40, 25, ustr "UseMenuAutoNavigation", true)
menuAutoMouseNav.Toggled.Add(MenuAutoMouseNav_Toggled)
ShowEntries (win)
let mutable (count : int) = 0
ml <- new Label(new Rect(3, 17, 47, 1), ustr "Mouse: ")
Application.RootMouseEvent <- Action<MouseEvent> (
fun (me : MouseEvent) ->
ml.TextColor <- Colors.TopLevel.Normal
ml.Text <- ustr (
(((sprintf "Mouse: (%O,%O) - %O %O" me.X) me.Y) me.Flags) (
count <- count + 1
count))
)
let mutable test = new Label(3, 18, ustr "Se iniciará el análisis")
win.Add (test)
win.Add (ml)
let mutable drag = new Label (ustr "Drag: ", X = Pos.At(70), Y = Pos.At(24))
let mutable dragText = new TextField (ustr "",
X = Pos.Right (drag),
Y = Pos.Top (drag),
Width = Dim.op_Implicit(40)
)
let mutable statusBar = new StatusBar ([|
new StatusItem(Key.F1, ustr "~F1~ Help", Action(Help));
new StatusItem(Key.F2, ustr "~F2~ Load", null);
new StatusItem(Key.F3, ustr "~F3~ Save", null);
new StatusItem(Key.ControlX, ustr "~^X~ Quit", fun () -> if (Quit ()) then top.Running <- false)
|],
Parent = null
)
win.Add (drag, dragText)
let mutable bottom = new Label(ustr "This should go on the bottom of the same top-level!")
win.Add (bottom)
let mutable bottom2 = new Label(ustr "This should go on the bottom of another top-level!")
top.Add (bottom2)
Application.OnLoad <- Action (
fun () ->
bottom.X <- win.X
bottom.Y <- Pos.Bottom (win) - Pos.Top (win) - Pos.At(margin)
bottom2.X <- Pos.Left (win)
bottom2.Y <- Pos.Bottom (win)
)
top.Add (win)
top.Add (menu, statusBar)
Application.Run ()
module Demo__run =
[<EntryPoint>]
let main argv =
Main ()
0

View File

@@ -121,6 +121,27 @@ namespace Terminal.Gui {
return false;
}
/// <summary>
/// Method invoked when a key is pressed.
/// </summary>
/// <param name="keyEvent">Contains the details about the key that produced the event.</param>
/// <returns>true if the event was handled</returns>
public virtual bool KeyDown (KeyEvent keyEvent)
{
return false;
}
/// <summary>
/// Method invoked when a key is released.
/// </summary>
/// <param name="keyEvent">Contains the details about the key that produced the event.</param>
/// <returns>true if the event was handled</returns>
public virtual bool KeyUp (KeyEvent keyEvent)
{
return false;
}
/// <summary>
/// Method invoked when a mouse event is generated
/// </summary>
@@ -1011,6 +1032,41 @@ namespace Terminal.Gui {
return false;
}
/// <summary>
/// Invoked when a key is pressed
/// </summary>
public Action<KeyEvent> OnKeyDown;
/// <param name="keyEvent">Contains the details about the key that produced the event.</param>
public override bool KeyDown (KeyEvent keyEvent)
{
OnKeyDown?.Invoke (keyEvent);
if (subviews == null || subviews.Count == 0)
return false;
foreach (var view in subviews)
if (view.KeyDown (keyEvent))
return true;
return false;
}
/// <summary>
/// Invoked when a key is released
/// </summary>
public Action<KeyEvent> OnKeyUp;
/// <param name="keyEvent">Contains the details about the key that produced the event.</param>
public override bool KeyUp (KeyEvent keyEvent)
{
OnKeyUp?.Invoke (keyEvent);
if (subviews == null || subviews.Count == 0)
return false;
foreach (var view in subviews)
if (view.KeyUp (keyEvent))
return true;
return false;
}
/// <summary>
/// Finds the first view in the hierarchy that wants to get the focus if nothing is currently focused, otherwise, it does nothing.
/// </summary>
@@ -1192,12 +1248,12 @@ namespace Terminal.Gui {
}
// https://en.wikipedia.org/wiki/Topological_sorting
static List<View> TopologicalSort (HashSet<View> nodes, HashSet<(View, View)> edges)
List<View> TopologicalSort (HashSet<View> nodes, HashSet<(View From, View To)> edges)
{
var result = new List<View> ();
// Set of all nodes with no incoming edges
var S = new HashSet<View> (nodes.Where (n => edges.All (e => e.Item2.Equals (n) == false)));
var S = new HashSet<View> (nodes.Where (n => edges.All (e => e.To.Equals (n) == false)));
while (S.Any ()) {
// remove a node n from S
@@ -1205,17 +1261,18 @@ namespace Terminal.Gui {
S.Remove (n);
// add n to tail of L
result.Add (n);
if (n != this?.SuperView)
result.Add (n);
// for each node m with an edge e from n to m do
foreach (var e in edges.Where (e => e.Item1.Equals (n)).ToList ()) {
var m = e.Item2;
foreach (var e in edges.Where (e => e.From.Equals (n)).ToArray ()) {
var m = e.To;
// remove edge e from the graph
edges.Remove (e);
// if m has no other incoming edges then
if (edges.All (me => me.Item2.Equals (m) == false)) {
if (edges.All (me => me.To.Equals (m) == false) && m != this?.SuperView) {
// insert m into S
S.Add (m);
}
@@ -1249,19 +1306,18 @@ namespace Terminal.Gui {
foreach (var v in InternalSubviews) {
nodes.Add (v);
if (v.LayoutStyle == LayoutStyle.Computed) {
if (v.X is Pos.PosView)
edges.Add ((v, (v.X as Pos.PosView).Target));
if (v.Y is Pos.PosView)
edges.Add ((v, (v.Y as Pos.PosView).Target));
if (v.Width is Dim.DimView)
edges.Add ((v, (v.Width as Dim.DimView).Target));
if (v.Height is Dim.DimView)
edges.Add ((v, (v.Height as Dim.DimView).Target));
if (v.X is Pos.PosView vX)
edges.Add ((vX.Target, v));
if (v.Y is Pos.PosView vY)
edges.Add ((vY.Target, v));
if (v.Width is Dim.DimView vWidth)
edges.Add ((vWidth.Target, v));
if (v.Height is Dim.DimView vHeight)
edges.Add ((vHeight.Target, v));
}
}
var ordered = TopologicalSort (nodes, edges);
ordered.Reverse ();
if (ordered == null)
throw new Exception ("There is a recursive cycle in the relative Pos/Dim in the views of " + this);
@@ -1269,11 +1325,15 @@ namespace Terminal.Gui {
if (v.LayoutStyle == LayoutStyle.Computed)
v.RelativeLayout (Frame);
if (this?.SuperView != v)
v.LayoutSubviews ();
v.LayoutSubviews ();
v.layoutNeeded = false;
}
if (SuperView == Application.Top && layoutNeeded && ordered.Count == 0 && LayoutStyle == LayoutStyle.Computed) {
RelativeLayout (Frame);
}
layoutNeeded = false;
}
@@ -1482,7 +1542,7 @@ namespace Terminal.Gui {
{
if (this != Application.Top) {
EnsureVisibleBounds (this, Frame.X, Frame.Y, out int nx, out int ny);
if (nx != Frame.X || ny != Frame.Y) {
if ((nx != Frame.X || ny != Frame.Y) && LayoutStyle != LayoutStyle.Computed) {
X = nx;
Y = ny;
}
@@ -1490,7 +1550,7 @@ namespace Terminal.Gui {
foreach (var top in Subviews) {
if (top is Toplevel) {
EnsureVisibleBounds ((Toplevel)top, top.Frame.X, top.Frame.Y, out int nx, out int ny);
if (nx != top.Frame.X || ny != top.Frame.Y) {
if ((nx != top.Frame.X || ny != top.Frame.Y) && top.LayoutStyle != LayoutStyle.Computed) {
top.X = nx;
top.Y = ny;
}
@@ -1513,7 +1573,7 @@ namespace Terminal.Gui {
}
foreach (var view in Subviews) {
if (view.Frame.IntersectsWith (region)) {
//view.SetNeedsLayout ();
view.SetNeedsLayout ();
view.SetNeedsDisplay (view.Bounds);
}
}
@@ -1943,6 +2003,7 @@ namespace Terminal.Gui {
static void ProcessKeyEvent (KeyEvent ke)
{
var chain = toplevels.ToList();
foreach (var topLevel in chain) {
if (topLevel.ProcessHotKey (ke))
@@ -1967,6 +2028,29 @@ namespace Terminal.Gui {
}
}
static void ProcessKeyDownEvent (KeyEvent ke)
{
var chain = toplevels.ToList ();
foreach (var topLevel in chain) {
if (topLevel.KeyDown (ke))
return;
if (topLevel.Modal)
break;
}
}
static void ProcessKeyUpEvent (KeyEvent ke)
{
var chain = toplevels.ToList ();
foreach (var topLevel in chain) {
if (topLevel.KeyUp (ke))
return;
if (topLevel.Modal)
break;
}
}
static View FindDeepestView (View start, int x, int y, out int resx, out int resy)
{
var startFrame = start.Frame;
@@ -2062,6 +2146,11 @@ namespace Terminal.Gui {
}
}
/// <summary>
/// Action that is invoked once at beginning.
/// </summary>
static public Action OnLoad;
/// <summary>
/// Building block API: Prepares the provided toplevel for execution.
/// </summary>
@@ -2092,10 +2181,11 @@ namespace Terminal.Gui {
}
toplevels.Push (toplevel);
Current = toplevel;
Driver.PrepareToRun (MainLoop, ProcessKeyEvent, ProcessMouseEvent);
Driver.PrepareToRun (MainLoop, ProcessKeyEvent, ProcessKeyDownEvent, ProcessKeyUpEvent, ProcessMouseEvent);
if (toplevel.LayoutStyle == LayoutStyle.Computed)
toplevel.RelativeLayout (new Rect (0, 0, Driver.Cols, Driver.Rows));
toplevel.LayoutSubviews ();
OnLoad?.Invoke ();
toplevel.WillPresent ();
Redraw (toplevel);
toplevel.PositionCursor ();

View File

@@ -469,7 +469,7 @@ namespace Terminal.Gui {
/// <param name="mainLoop"></param>
/// <param name="keyHandler"></param>
/// <param name="mouseHandler"></param>
public abstract void PrepareToRun (MainLoop mainLoop, Action<KeyEvent> keyHandler, Action<MouseEvent> mouseHandler);
public abstract void PrepareToRun (MainLoop mainLoop, Action<KeyEvent> keyHandler, Action<KeyEvent> keyDownHandler, Action<KeyEvent> keyUpHandler, Action<MouseEvent> mouseHandler);
/// <summary>
/// Updates the screen to reflect all the changes that have been done to the display buffer

View File

@@ -203,8 +203,9 @@ namespace Terminal.Gui {
keyHandler (new KeyEvent ((Key)wch));
}
public override void PrepareToRun (MainLoop mainLoop, Action<KeyEvent> keyHandler, Action<MouseEvent> mouseHandler)
public override void PrepareToRun (MainLoop mainLoop, Action<KeyEvent> keyHandler, Action<KeyEvent> keyDownHandler, Action<KeyEvent> keyUpHandler, Action<MouseEvent> mouseHandler)
{
// Note: Curses doesn't support keydown/up events and thus any passed keyDown/UpHandlers will never be called
Curses.timeout (-1);
(mainLoop.Driver as Mono.Terminal.UnixMainLoop).AddWatch (0, Mono.Terminal.UnixMainLoop.Condition.PollIn, x => {

View File

@@ -320,8 +320,9 @@ namespace Terminal.Gui {
return (Key)(0xffffffff);
}
public override void PrepareToRun (MainLoop mainLoop, Action<KeyEvent> keyHandler, Action<MouseEvent> mouseHandler)
public override void PrepareToRun (MainLoop mainLoop, Action<KeyEvent> keyHandler, Action<KeyEvent> keyDownHandler, Action<KeyEvent> keyUpHandler, Action<MouseEvent> mouseHandler)
{
// Note: Net doesn't support keydown/up events and thus any passed keyDown/UpHandlers will never be called
(mainLoop.Driver as NetMainLoop).WindowsKeyPressed = delegate (ConsoleKeyInfo consoleKey) {
var map = MapKey (consoleKey);
if (map == (Key)0xffffffff)

View File

@@ -26,6 +26,7 @@
// SOFTWARE.
//
using System;
using System.CodeDom;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
@@ -102,7 +103,7 @@ namespace Terminal.Gui {
}
if (ScreenBuffer != IntPtr.Zero)
CloseHandle(ScreenBuffer);
CloseHandle (ScreenBuffer);
ScreenBuffer = IntPtr.Zero;
}
@@ -358,8 +359,8 @@ namespace Terminal.Gui {
[DllImport ("kernel32.dll", SetLastError = true)]
static extern IntPtr GetStdHandle (int nStdHandle);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr handle);
[DllImport ("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle (IntPtr handle);
[DllImport ("kernel32.dll", EntryPoint = "ReadConsoleInputW", CharSet = CharSet.Unicode)]
public static extern bool ReadConsoleInput (
@@ -424,8 +425,8 @@ namespace Terminal.Gui {
internal class WindowsDriver : ConsoleDriver, Mono.Terminal.IMainLoopDriver {
static bool sync;
ManualResetEventSlim eventReady = new ManualResetEventSlim(false);
ManualResetEventSlim waitForProbe = new ManualResetEventSlim(false);
ManualResetEventSlim eventReady = new ManualResetEventSlim (false);
ManualResetEventSlim waitForProbe = new ManualResetEventSlim (false);
MainLoop mainLoop;
WindowsConsole.CharInfo [] OutputBuffer;
int cols, rows;
@@ -456,17 +457,17 @@ namespace Terminal.Gui {
Task.Run ((Action)WindowsInputHandler);
}
[StructLayout(LayoutKind.Sequential)]
[StructLayout (LayoutKind.Sequential)]
public struct ConsoleKeyInfoEx {
public ConsoleKeyInfo consoleKeyInfo;
public bool CapsLock;
public bool NumLock;
public ConsoleKeyInfoEx(ConsoleKeyInfo consoleKeyInfo, bool capslock, bool numlock)
public ConsoleKeyInfoEx (ConsoleKeyInfo consoleKeyInfo, bool capslock, bool numlock)
{
this.consoleKeyInfo = consoleKeyInfo;
CapsLock = capslock;
NumLock = numlock;
this.consoleKeyInfo = consoleKeyInfo;
CapsLock = capslock;
NumLock = numlock;
}
}
@@ -476,8 +477,8 @@ namespace Terminal.Gui {
void WindowsInputHandler ()
{
while (true) {
waitForProbe.Wait();
waitForProbe.Reset();
waitForProbe.Wait ();
waitForProbe.Reset ();
uint numberEventsRead = 0;
@@ -487,7 +488,7 @@ namespace Terminal.Gui {
else
result = records;
eventReady.Set();
eventReady.Set ();
}
}
@@ -498,7 +499,9 @@ namespace Terminal.Gui {
void IMainLoopDriver.Wakeup ()
{
tokenSource.Cancel();
//tokenSource.Cancel ();
eventReady.Reset ();
eventReady.Set ();
}
bool IMainLoopDriver.EventsPending (bool wait)
@@ -517,31 +520,35 @@ namespace Terminal.Gui {
waitTimeout = 0;
result = null;
waitForProbe.Set();
waitForProbe.Set ();
try {
if(!tokenSource.IsCancellationRequested)
eventReady.Wait(waitTimeout, tokenSource.Token);
if (!tokenSource.IsCancellationRequested)
eventReady.Wait (waitTimeout, tokenSource.Token);
} catch (OperationCanceledException) {
return true;
} finally {
eventReady.Reset();
eventReady.Reset ();
}
if (!tokenSource.IsCancellationRequested)
return result != null;
tokenSource.Dispose();
tokenSource = new CancellationTokenSource();
tokenSource.Dispose ();
tokenSource = new CancellationTokenSource ();
return true;
}
Action<KeyEvent> keyHandler;
Action<KeyEvent> keyDownHandler;
Action<KeyEvent> keyUpHandler;
Action<MouseEvent> mouseHandler;
public override void PrepareToRun (MainLoop mainLoop, Action<KeyEvent> keyHandler, Action<MouseEvent> mouseHandler)
public override void PrepareToRun (MainLoop mainLoop, Action<KeyEvent> keyHandler, Action<KeyEvent> keyDownHandler, Action<KeyEvent> keyUpHandler, Action<MouseEvent> mouseHandler)
{
this.keyHandler = keyHandler;
this.keyDownHandler = keyDownHandler;
this.keyUpHandler = keyUpHandler;
this.mouseHandler = mouseHandler;
}
@@ -554,16 +561,43 @@ namespace Terminal.Gui {
var inputEvent = result [0];
switch (inputEvent.EventType) {
case WindowsConsole.EventType.Key:
if (inputEvent.KeyEvent.bKeyDown == false)
return;
var map = MapKey (ToConsoleKeyInfoEx (inputEvent.KeyEvent));
if (inputEvent.KeyEvent.UnicodeChar == 0 && map == (Key)0xffffffff)
return;
keyHandler (new KeyEvent (map));
if (map == (Key)0xffffffff) {
KeyEvent key;
// Shift = VK_SHIFT = 0x10
// Ctrl = VK_CONTROL = 0x11
// Alt = VK_MENU = 0x12
switch (inputEvent.KeyEvent.wVirtualKeyCode) {
case 0x11:
key = new KeyEvent (Key.CtrlMask);
break;
case 0x12:
key = new KeyEvent (Key.AltMask);
break;
default:
key = new KeyEvent (Key.Unknown);
break;
}
if (inputEvent.KeyEvent.bKeyDown)
keyDownHandler (key);
else
keyUpHandler (key);
} else {
if (inputEvent.KeyEvent.bKeyDown) {
// Key Down - Fire KeyDown Event and KeyStroke (ProcessKey) Event
keyDownHandler (new KeyEvent (map));
keyHandler (new KeyEvent (map));
} else {
keyUpHandler (new KeyEvent (map));
}
}
break;
case WindowsConsole.EventType.Mouse:
mouseHandler (ToDriverMouse (inputEvent.MouseEvent));
if (IsButtonReleased)
mouseHandler (ToDriverMouse (inputEvent.MouseEvent));
break;
case WindowsConsole.EventType.WindowBufferSize:
@@ -571,15 +605,17 @@ namespace Terminal.Gui {
rows = inputEvent.WindowBufferSizeEvent.size.Y;
ResizeScreen ();
UpdateOffScreen ();
TerminalResized?.Invoke();
TerminalResized?.Invoke ();
break;
}
result = null;
}
WindowsConsole.ButtonState? LastMouseButtonPressed = null;
bool IsButtonPressed = false;
bool IsButtonReleased = false;
bool IsButtonDoubleClicked = false;
Point point;
MouseEvent ToDriverMouse (WindowsConsole.MouseEventRecord mouseEvent)
{
@@ -587,8 +623,8 @@ namespace Terminal.Gui {
if (IsButtonDoubleClicked) {
Task.Run (async () => {
await Task.Delay (300);
_ = new Action (() => IsButtonDoubleClicked = false);
await Task.Delay (100);
IsButtonDoubleClicked = false;
});
}
@@ -599,12 +635,13 @@ namespace Terminal.Gui {
// map to the correct clicked event.
if ((LastMouseButtonPressed != null || IsButtonReleased) && mouseEvent.ButtonState != 0) {
LastMouseButtonPressed = null;
IsButtonPressed = false;
IsButtonReleased = false;
}
if ((mouseEvent.EventFlags == 0 && LastMouseButtonPressed == null && !IsButtonDoubleClicked) ||
(mouseEvent.EventFlags == WindowsConsole.EventFlags.MouseMoved &&
mouseEvent.ButtonState != 0 && !IsButtonDoubleClicked)) {
mouseEvent.ButtonState != 0 && !IsButtonReleased && !IsButtonDoubleClicked)) {
switch (mouseEvent.ButtonState) {
case WindowsConsole.ButtonState.Button1Pressed:
mouseFlag = MouseFlags.Button1Pressed;
@@ -619,11 +656,39 @@ namespace Terminal.Gui {
break;
}
if (mouseEvent.EventFlags == WindowsConsole.EventFlags.MouseMoved)
if (mouseEvent.EventFlags == WindowsConsole.EventFlags.MouseMoved) {
mouseFlag |= MouseFlags.ReportMousePosition;
point = new Point ();
IsButtonReleased = false;
} else {
point = new Point () {
X = mouseEvent.MousePosition.X,
Y = mouseEvent.MousePosition.Y
};
}
LastMouseButtonPressed = mouseEvent.ButtonState;
} else if (mouseEvent.EventFlags == 0 && LastMouseButtonPressed != null && !IsButtonReleased &&
!IsButtonDoubleClicked) {
IsButtonPressed = true;
if ((mouseFlag & MouseFlags.ReportMousePosition) == 0) {
Task.Run (async () => {
while (IsButtonPressed) {
await Task.Delay (200);
var me = new MouseEvent () {
X = mouseEvent.MousePosition.X,
Y = mouseEvent.MousePosition.Y,
Flags = mouseFlag
};
if (IsButtonPressed && (mouseFlag & MouseFlags.ReportMousePosition) == 0) {
mouseHandler (me);
mainLoop.Driver.Wakeup ();
}
}
});
}
} else if ((mouseEvent.EventFlags == 0 || mouseEvent.EventFlags == WindowsConsole.EventFlags.MouseMoved) &&
LastMouseButtonPressed != null && !IsButtonReleased && !IsButtonDoubleClicked) {
switch (LastMouseButtonPressed) {
case WindowsConsole.ButtonState.Button1Pressed:
mouseFlag = MouseFlags.Button1Released;
@@ -637,21 +702,30 @@ namespace Terminal.Gui {
mouseFlag = MouseFlags.Button4Released;
break;
}
IsButtonPressed = false;
IsButtonReleased = true;
} else if ((mouseEvent.EventFlags == 0 || mouseEvent.EventFlags == WindowsConsole.EventFlags.MouseMoved) &&
IsButtonReleased) {
switch (LastMouseButtonPressed) {
case WindowsConsole.ButtonState.Button1Pressed:
mouseFlag = MouseFlags.Button1Clicked;
break;
IsButtonReleased) {
var p = new Point () {
X = mouseEvent.MousePosition.X,
Y = mouseEvent.MousePosition.Y
};
if (p == point) {
switch (LastMouseButtonPressed) {
case WindowsConsole.ButtonState.Button1Pressed:
mouseFlag = MouseFlags.Button1Clicked;
break;
case WindowsConsole.ButtonState.Button2Pressed:
mouseFlag = MouseFlags.Button2Clicked;
break;
case WindowsConsole.ButtonState.Button2Pressed:
mouseFlag = MouseFlags.Button2Clicked;
break;
case WindowsConsole.ButtonState.RightmostButtonPressed:
mouseFlag = MouseFlags.Button4Clicked;
break;
case WindowsConsole.ButtonState.RightmostButtonPressed:
mouseFlag = MouseFlags.Button4Clicked;
break;
}
} else {
mouseFlag = 0;
}
LastMouseButtonPressed = null;
IsButtonReleased = false;
@@ -734,8 +808,8 @@ namespace Terminal.Gui {
bool capslock = (state & (WindowsConsole.ControlKeyState.CapslockOn)) != 0;
bool numlock = (state & (WindowsConsole.ControlKeyState.NumlockOn)) != 0;
var ConsoleKeyInfo = new ConsoleKeyInfo(keyEvent.UnicodeChar, (ConsoleKey)keyEvent.wVirtualKeyCode, shift, alt, control);
return new ConsoleKeyInfoEx(ConsoleKeyInfo, capslock, numlock);
var ConsoleKeyInfo = new ConsoleKeyInfo (keyEvent.UnicodeChar, (ConsoleKey)keyEvent.wVirtualKeyCode, shift, alt, control);
return new ConsoleKeyInfoEx (ConsoleKeyInfo, capslock, numlock);
}
public Key MapKey (ConsoleKeyInfoEx keyInfoEx)
@@ -837,6 +911,7 @@ namespace Terminal.Gui {
return (Key)((int)Key.F1 + delta);
}
return (Key)(0xffffffff);
}
@@ -871,7 +946,7 @@ namespace Terminal.Gui {
Colors.Menu.Focus = MakeColor (ConsoleColor.White, ConsoleColor.Black);
Colors.Menu.HotNormal = MakeColor (ConsoleColor.Yellow, ConsoleColor.Cyan);
Colors.Menu.HotFocus = MakeColor (ConsoleColor.Yellow, ConsoleColor.Black);
Colors.Menu.Disabled = MakeColor(ConsoleColor.DarkGray, ConsoleColor.Cyan);
Colors.Menu.Disabled = MakeColor (ConsoleColor.DarkGray, ConsoleColor.Cyan);
Colors.Dialog.Normal = MakeColor (ConsoleColor.Black, ConsoleColor.Gray);
Colors.Dialog.Focus = MakeColor (ConsoleColor.Black, ConsoleColor.Cyan);
@@ -925,10 +1000,10 @@ namespace Terminal.Gui {
}
ccol++;
var runeWidth = Rune.ColumnWidth(rune);
var runeWidth = Rune.ColumnWidth (rune);
if (runeWidth > 1) {
for (int i = 1; i < runeWidth; i++) {
AddStr(" ");
AddStr (" ");
}
}
if (ccol == Cols) {
@@ -947,7 +1022,7 @@ namespace Terminal.Gui {
}
int currentAttribute;
CancellationTokenSource tokenSource = new CancellationTokenSource();
CancellationTokenSource tokenSource = new CancellationTokenSource ();
public override void SetAttribute (Attribute c)
{
@@ -995,39 +1070,39 @@ namespace Terminal.Gui {
if (damageRegion.Left == -1)
return;
var bufferCoords = new WindowsConsole.Coord (){
var bufferCoords = new WindowsConsole.Coord () {
X = (short)Clip.Width,
Y = (short)Clip.Height
};
var window = new WindowsConsole.SmallRect (){
var window = new WindowsConsole.SmallRect () {
Top = 0,
Left = 0,
Right = (short)Clip.Right,
Bottom = (short)Clip.Bottom
};
UpdateCursor();
UpdateCursor ();
winConsole.WriteToConsole (OutputBuffer, bufferCoords, damageRegion);
// System.Diagnostics.Debugger.Log(0, "debug", $"Region={damageRegion.Right - damageRegion.Left},{damageRegion.Bottom - damageRegion.Top}\n");
// System.Diagnostics.Debugger.Log(0, "debug", $"Region={damageRegion.Right - damageRegion.Left},{damageRegion.Bottom - damageRegion.Top}\n");
WindowsConsole.SmallRect.MakeEmpty (ref damageRegion);
}
public override void UpdateCursor()
public override void UpdateCursor ()
{
var position = new WindowsConsole.Coord(){
var position = new WindowsConsole.Coord () {
X = (short)ccol,
Y = (short)crow
};
winConsole.SetCursorPosition(position);
winConsole.SetCursorPosition (position);
}
public override void End ()
{
winConsole.Cleanup();
winConsole.Cleanup ();
}
#region Unused
#region Unused
public override void SetColors (ConsoleColor foreground, ConsoleColor background)
{
}
@@ -1055,7 +1130,7 @@ namespace Terminal.Gui {
public override void CookMouse ()
{
}
#endregion
#endregion
}

View File

@@ -1,840 +0,0 @@
//
// WindowsDriver.cs: Windows specific driver
//
// Authors:
// Miguel de Icaza (miguel@gnome.org)
// Nick Van Dyck (vandyck.nick@outlook.com)
//
// Copyright (c) 2018
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Mono.Terminal;
using NStack;
namespace Terminal.Gui {
internal class WindowsConsole {
public const int STD_OUTPUT_HANDLE = -11;
public const int STD_INPUT_HANDLE = -10;
public const int STD_ERROR_HANDLE = -12;
internal IntPtr InputHandle, OutputHandle;
IntPtr ScreenBuffer;
uint originalConsoleMode;
public WindowsConsole ()
{
InputHandle = GetStdHandle (STD_INPUT_HANDLE);
OutputHandle = GetStdHandle (STD_OUTPUT_HANDLE);
originalConsoleMode = ConsoleMode;
var newConsoleMode = originalConsoleMode;
newConsoleMode |= (uint)(ConsoleModes.EnableMouseInput | ConsoleModes.EnableExtendedFlags);
newConsoleMode &= ~(uint)ConsoleModes.EnableQuickEditMode;
ConsoleMode = newConsoleMode;
}
public CharInfo[] OriginalStdOutChars;
public bool WriteToConsole (CharInfo[] charInfoBuffer, Coord coords, SmallRect window)
{
if (ScreenBuffer == IntPtr.Zero)
{
ScreenBuffer = CreateConsoleScreenBuffer (
DesiredAccess.GenericRead | DesiredAccess.GenericWrite,
ShareMode.FileShareRead | ShareMode.FileShareWrite,
IntPtr.Zero,
1,
IntPtr.Zero
);
if (ScreenBuffer == INVALID_HANDLE_VALUE){
var err = Marshal.GetLastWin32Error ();
if (err != 0)
throw new System.ComponentModel.Win32Exception(err);
}
if (!SetConsoleActiveScreenBuffer (ScreenBuffer)){
var err = Marshal.GetLastWin32Error();
throw new System.ComponentModel.Win32Exception(err);
}
OriginalStdOutChars = new CharInfo[Console.WindowHeight * Console.WindowWidth];
ReadConsoleOutput (OutputHandle, OriginalStdOutChars, coords, new Coord () { X = 0, Y = 0 }, ref window);
}
return WriteConsoleOutput (ScreenBuffer, charInfoBuffer, coords, new Coord () { X = 0, Y = 0 }, ref window);
}
public bool SetCursorPosition(Coord position)
{
return SetConsoleCursorPosition (ScreenBuffer, position);
}
public void Cleanup ()
{
ContinueListeningForConsoleEvents = false;
if (!SetConsoleActiveScreenBuffer (OutputHandle)){
var err = Marshal.GetLastWin32Error ();
Console.WriteLine("Error: {0}", err);
}
}
private bool ContinueListeningForConsoleEvents = true;
public uint ConsoleMode {
get {
uint v;
GetConsoleMode (InputHandle, out v);
return v;
}
set {
SetConsoleMode (InputHandle, value);
}
}
[Flags]
public enum ConsoleModes : uint
{
EnableMouseInput = 16,
EnableQuickEditMode = 64,
EnableExtendedFlags = 128,
}
[StructLayout (LayoutKind.Explicit, CharSet = CharSet.Unicode)]
public struct KeyEventRecord {
[FieldOffset (0), MarshalAs (UnmanagedType.Bool)]
public bool bKeyDown;
[FieldOffset (4), MarshalAs (UnmanagedType.U2)]
public ushort wRepeatCount;
[FieldOffset (6), MarshalAs (UnmanagedType.U2)]
public ushort wVirtualKeyCode;
[FieldOffset (8), MarshalAs (UnmanagedType.U2)]
public ushort wVirtualScanCode;
[FieldOffset (10)]
public char UnicodeChar;
[FieldOffset (12), MarshalAs (UnmanagedType.U4)]
public ControlKeyState dwControlKeyState;
}
[Flags]
public enum ButtonState {
Button1Pressed = 1,
Button2Pressed = 4,
Button3Pressed = 8,
Button4Pressed = 16,
RightmostButtonPressed = 2,
}
[Flags]
public enum ControlKeyState {
RightAltPressed = 1,
LeftAltPressed = 2,
RightControlPressed = 4,
LeftControlPressed = 8,
ShiftPressed = 16,
NumlockOn = 32,
ScrolllockOn = 64,
CapslockOn = 128,
EnhancedKey = 256
}
[Flags]
public enum EventFlags {
MouseMoved = 1,
DoubleClick = 2,
MouseWheeled = 4,
MouseHorizontalWheeled = 8
}
[StructLayout (LayoutKind.Explicit)]
public struct MouseEventRecord {
[FieldOffset (0)]
public Coordinate MousePosition;
[FieldOffset (4)]
public ButtonState ButtonState;
[FieldOffset (8)]
public ControlKeyState ControlKeyState;
[FieldOffset (12)]
public EventFlags EventFlags;
public override string ToString ()
{
return $"[Mouse({MousePosition},{ButtonState},{ControlKeyState},{EventFlags}";
}
}
[StructLayout (LayoutKind.Sequential)]
public struct Coordinate {
public short X;
public short Y;
public Coordinate (short X, short Y)
{
this.X = X;
this.Y = Y;
}
public override string ToString () => $"({X},{Y})";
};
internal struct WindowBufferSizeRecord {
public Coordinate size;
public WindowBufferSizeRecord (short x, short y)
{
this.size = new Coordinate (x, y);
}
public override string ToString () => $"[WindowBufferSize{size}";
}
[StructLayout (LayoutKind.Sequential)]
public struct MenuEventRecord {
public uint dwCommandId;
}
[StructLayout (LayoutKind.Sequential)]
public struct FocusEventRecord {
public uint bSetFocus;
}
public enum EventType {
Focus = 0x10,
Key = 0x1,
Menu = 0x8,
Mouse = 2,
WindowBufferSize = 4
}
[StructLayout (LayoutKind.Explicit)]
public struct InputRecord {
[FieldOffset (0)]
public EventType EventType;
[FieldOffset (4)]
public KeyEventRecord KeyEvent;
[FieldOffset (4)]
public MouseEventRecord MouseEvent;
[FieldOffset (4)]
public WindowBufferSizeRecord WindowBufferSizeEvent;
[FieldOffset (4)]
public MenuEventRecord MenuEvent;
[FieldOffset (4)]
public FocusEventRecord FocusEvent;
public override string ToString ()
{
switch (EventType) {
case EventType.Focus:
return FocusEvent.ToString ();
case EventType.Key:
return KeyEvent.ToString ();
case EventType.Menu:
return MenuEvent.ToString ();
case EventType.Mouse:
return MouseEvent.ToString ();
case EventType.WindowBufferSize:
return WindowBufferSizeEvent.ToString ();
default:
return "Unknown event type: " + EventType;
}
}
};
[Flags]
enum ShareMode : uint
{
FileShareRead = 1,
FileShareWrite = 2,
}
[Flags]
enum DesiredAccess : uint
{
GenericRead = 2147483648,
GenericWrite = 1073741824,
}
[StructLayout(LayoutKind.Sequential)]
public struct ConsoleScreenBufferInfo
{
public Coord dwSize;
public Coord dwCursorPosition;
public ushort wAttributes;
public SmallRect srWindow;
public Coord dwMaximumWindowSize;
}
[StructLayout(LayoutKind.Sequential)]
public struct Coord
{
public short X;
public short Y;
public Coord(short X, short Y)
{
this.X = X;
this.Y = Y;
}
};
[StructLayout(LayoutKind.Explicit, CharSet=CharSet.Unicode)]
public struct CharUnion
{
[FieldOffset(0)] public char UnicodeChar;
[FieldOffset(0)] public byte AsciiChar;
}
[StructLayout(LayoutKind.Explicit, CharSet=CharSet.Unicode)]
public struct CharInfo
{
[FieldOffset(0)] public CharUnion Char;
[FieldOffset(2)] public ushort Attributes;
}
[StructLayout(LayoutKind.Sequential)]
public struct SmallRect
{
public short Left;
public short Top;
public short Right;
public short Bottom;
}
[DllImport ("kernel32.dll", SetLastError = true)]
static extern IntPtr GetStdHandle (int nStdHandle);
[DllImport ("kernel32.dll", EntryPoint = "ReadConsoleInputW", CharSet = CharSet.Unicode)]
public static extern bool ReadConsoleInput (
IntPtr hConsoleInput,
[Out] InputRecord [] lpBuffer,
uint nLength,
out uint lpNumberOfEventsRead);
[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
static extern bool ReadConsoleOutput(
IntPtr hConsoleOutput,
[Out] CharInfo[] lpBuffer,
Coord dwBufferSize,
Coord dwBufferCoord,
ref SmallRect lpReadRegion
);
[DllImport("kernel32.dll", EntryPoint="WriteConsoleOutput", SetLastError=true, CharSet=CharSet.Unicode)]
static extern bool WriteConsoleOutput(
IntPtr hConsoleOutput,
CharInfo[] lpBuffer,
Coord dwBufferSize,
Coord dwBufferCoord,
ref SmallRect lpWriteRegion
);
[DllImport ("kernel32.dll")]
static extern bool SetConsoleCursorPosition(IntPtr hConsoleOutput, Coord dwCursorPosition);
[DllImport ("kernel32.dll")]
static extern bool GetConsoleMode (IntPtr hConsoleHandle, out uint lpMode);
[DllImport ("kernel32.dll")]
static extern bool SetConsoleMode (IntPtr hConsoleHandle, uint dwMode);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr CreateConsoleScreenBuffer(
DesiredAccess dwDesiredAccess,
ShareMode dwShareMode,
IntPtr secutiryAttributes,
UInt32 flags,
IntPtr screenBufferData
);
internal static IntPtr INVALID_HANDLE_VALUE = new IntPtr (-1);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool SetConsoleActiveScreenBuffer(IntPtr Handle);
[DllImport ("kernel32.dll", SetLastError = true)]
static extern bool GetNumberOfConsoleInputEvents (IntPtr handle, out uint lpcNumberOfEvents);
public uint InputEventCount {
get {
uint v;
GetNumberOfConsoleInputEvents (InputHandle, out v);
return v;
}
}
}
internal class WindowsDriver : ConsoleDriver, Mono.Terminal.IMainLoopDriver {
static bool sync;
AutoResetEvent eventReady = new AutoResetEvent (false);
AutoResetEvent waitForProbe = new AutoResetEvent (false);
MainLoop mainLoop;
Action TerminalResized;
WindowsConsole.CharInfo[] OutputBuffer;
int cols, rows;
WindowsConsole winConsole;
public override int Cols => cols;
public override int Rows => rows;
public WindowsDriver ()
{
winConsole = new WindowsConsole();
cols = Console.WindowWidth;
rows = Console.WindowHeight - 1;
ResizeScreen ();
UpdateOffScreen ();
Task.Run ((Action)WindowsInputHandler);
}
// The records that we keep fetching
WindowsConsole.InputRecord [] result, records = new WindowsConsole.InputRecord [1];
void WindowsInputHandler ()
{
while (true) {
waitForProbe.WaitOne ();
uint numberEventsRead = 0;
WindowsConsole.ReadConsoleInput (winConsole.InputHandle, records, 1, out numberEventsRead);
if (numberEventsRead == 0)
result = null;
else
result = records;
eventReady.Set ();
}
}
void IMainLoopDriver.Setup (MainLoop mainLoop)
{
this.mainLoop = mainLoop;
}
void IMainLoopDriver.Wakeup ()
{
}
bool IMainLoopDriver.EventsPending (bool wait)
{
long now = DateTime.UtcNow.Ticks;
int waitTimeout;
if (mainLoop.timeouts.Count > 0) {
waitTimeout = (int)((mainLoop.timeouts.Keys [0] - now) / TimeSpan.TicksPerMillisecond);
if (waitTimeout < 0)
return true;
} else
waitTimeout = -1;
if (!wait)
waitTimeout = 0;
result = null;
waitForProbe.Set ();
eventReady.WaitOne (waitTimeout);
return result != null;
}
Action<KeyEvent> keyHandler;
Action<MouseEvent> mouseHandler;
public override void PrepareToRun (MainLoop mainLoop, Action<KeyEvent> keyHandler, Action<MouseEvent> mouseHandler)
{
this.keyHandler = keyHandler;
this.mouseHandler = mouseHandler;
}
void IMainLoopDriver.MainIteration ()
{
if (result == null)
return;
var inputEvent = result [0];
switch (inputEvent.EventType) {
case WindowsConsole.EventType.Key:
if (inputEvent.KeyEvent.bKeyDown == false)
return;
var map = MapKey (ToConsoleKeyInfo (inputEvent.KeyEvent));
if (map == (Key)0xffffffff)
return;
keyHandler (new KeyEvent (map));
break;
case WindowsConsole.EventType.Mouse:
mouseHandler (ToDriverMouse (inputEvent.MouseEvent));
break;
case WindowsConsole.EventType.WindowBufferSize:
cols = inputEvent.WindowBufferSizeEvent.size.X;
rows = inputEvent.WindowBufferSizeEvent.size.Y - 1;
ResizeScreen ();
UpdateOffScreen ();
TerminalResized ();
break;
}
result = null;
}
private WindowsConsole.ButtonState? LastMouseButtonPressed = null;
private MouseEvent ToDriverMouse(WindowsConsole.MouseEventRecord mouseEvent)
{
MouseFlags mouseFlag = MouseFlags.AllEvents;
// The ButtonState member of the MouseEvent structure has bit corresponding to each mouse button.
// This will tell when a mouse button is pressed. When the button is released this event will
// be fired with it's bit set to 0. So when the button is up ButtonState will be 0.
// To map to the correct driver events we save the last pressed mouse button so we can
// map to the correct clicked event.
if (LastMouseButtonPressed != null && mouseEvent.ButtonState != 0)
{
LastMouseButtonPressed = null;
}
if (mouseEvent.EventFlags == 0 && LastMouseButtonPressed == null){
switch (mouseEvent.ButtonState){
case WindowsConsole.ButtonState.Button1Pressed:
mouseFlag = MouseFlags.Button1Pressed;
break;
case WindowsConsole.ButtonState.Button2Pressed:
mouseFlag = MouseFlags.Button2Pressed;
break;
case WindowsConsole.ButtonState.Button3Pressed:
mouseFlag = MouseFlags.Button3Pressed;
break;
}
LastMouseButtonPressed = mouseEvent.ButtonState;
} else if (mouseEvent.EventFlags == 0 && LastMouseButtonPressed != null){
switch (LastMouseButtonPressed){
case WindowsConsole.ButtonState.Button1Pressed:
mouseFlag = MouseFlags.Button1Clicked;
break;
case WindowsConsole.ButtonState.Button2Pressed:
mouseFlag = MouseFlags.Button2Clicked;
break;
case WindowsConsole.ButtonState.Button3Pressed:
mouseFlag = MouseFlags.Button3Clicked;
break;
}
LastMouseButtonPressed = null;
} else if(mouseEvent.EventFlags == WindowsConsole.EventFlags.MouseMoved){
mouseFlag = MouseFlags.ReportMousePosition;
}
return new MouseEvent () {
X = mouseEvent.MousePosition.X,
Y = mouseEvent.MousePosition.Y,
Flags = mouseFlag
};
}
private ConsoleKeyInfo ToConsoleKeyInfo (WindowsConsole.KeyEventRecord keyEvent)
{
var state = keyEvent.dwControlKeyState;
bool shift = (state & WindowsConsole.ControlKeyState.ShiftPressed) != 0;
bool alt = (state & (WindowsConsole.ControlKeyState.LeftAltPressed | WindowsConsole.ControlKeyState.RightAltPressed)) != 0;
bool control = (state & (WindowsConsole.ControlKeyState.LeftControlPressed | WindowsConsole.ControlKeyState.RightControlPressed)) != 0;
return new ConsoleKeyInfo(keyEvent.UnicodeChar, (ConsoleKey)keyEvent.wVirtualKeyCode, shift, alt, control);
}
public Key MapKey (ConsoleKeyInfo keyInfo)
{
switch (keyInfo.Key) {
case ConsoleKey.Escape:
return Key.Esc;
case ConsoleKey.Tab:
return Key.Tab;
case ConsoleKey.Home:
return Key.Home;
case ConsoleKey.End:
return Key.End;
case ConsoleKey.LeftArrow:
return Key.CursorLeft;
case ConsoleKey.RightArrow:
return Key.CursorRight;
case ConsoleKey.UpArrow:
return Key.CursorUp;
case ConsoleKey.DownArrow:
return Key.CursorDown;
case ConsoleKey.PageUp:
return Key.PageUp;
case ConsoleKey.PageDown:
return Key.PageDown;
case ConsoleKey.Enter:
return Key.Enter;
case ConsoleKey.Spacebar:
return Key.Space;
case ConsoleKey.Backspace:
return Key.Backspace;
case ConsoleKey.Delete:
return Key.DeleteChar;
case ConsoleKey.Oem1:
case ConsoleKey.Oem2:
case ConsoleKey.Oem3:
case ConsoleKey.Oem4:
case ConsoleKey.Oem5:
case ConsoleKey.Oem6:
case ConsoleKey.Oem7:
case ConsoleKey.Oem8:
case ConsoleKey.Oem102:
case ConsoleKey.OemPeriod:
case ConsoleKey.OemComma:
case ConsoleKey.OemPlus:
case ConsoleKey.OemMinus:
return (Key)((uint)keyInfo.KeyChar);
}
var key = keyInfo.Key;
if (key >= ConsoleKey.A && key <= ConsoleKey.Z) {
var delta = key - ConsoleKey.A;
if (keyInfo.Modifiers == ConsoleModifiers.Control)
return (Key)((uint)Key.ControlA + delta);
if (keyInfo.Modifiers == ConsoleModifiers.Alt)
return (Key)(((uint)Key.AltMask) | ((uint)'A' + delta));
if (keyInfo.Modifiers == ConsoleModifiers.Shift)
return (Key)((uint)'A' + delta);
else
return (Key)((uint)'a' + delta);
}
if (key >= ConsoleKey.D0 && key <= ConsoleKey.D9) {
var delta = key - ConsoleKey.D0;
if (keyInfo.Modifiers == ConsoleModifiers.Alt)
return (Key)(((uint)Key.AltMask) | ((uint)'0' + delta));
if (keyInfo.Modifiers == ConsoleModifiers.Shift)
return (Key)((uint)keyInfo.KeyChar);
return (Key)((uint)'0' + delta);
}
if (key >= ConsoleKey.F1 && key <= ConsoleKey.F10) {
var delta = key - ConsoleKey.F1;
return (Key)((int)Key.F1 + delta);
}
return (Key)(0xffffffff);
}
public override void Init (Action terminalResized)
{
TerminalResized = terminalResized;
Colors.Base = new ColorScheme ();
Colors.Dialog = new ColorScheme ();
Colors.Menu = new ColorScheme ();
Colors.Error = new ColorScheme ();
HLine = '\u2500';
VLine = '\u2502';
Stipple = '\u2592';
Diamond = '\u25c6';
ULCorner = '\u250C';
LLCorner = '\u2514';
URCorner = '\u2510';
LRCorner = '\u2518';
LeftTee = '\u251c';
RightTee = '\u2524';
TopTee = '\u22a4';
BottomTee = '\u22a5';
Colors.Base.Normal = MakeColor (ConsoleColor.White, ConsoleColor.Blue);
Colors.Base.Focus = MakeColor (ConsoleColor.Black, ConsoleColor.Cyan);
Colors.Base.HotNormal = MakeColor (ConsoleColor.Yellow, ConsoleColor.Blue);
Colors.Base.HotFocus = MakeColor (ConsoleColor.Yellow, ConsoleColor.Cyan);
Colors.Menu.HotFocus = MakeColor (ConsoleColor.Yellow, ConsoleColor.Black);
Colors.Menu.Focus = MakeColor (ConsoleColor.White, ConsoleColor.Black);
Colors.Menu.HotNormal = MakeColor (ConsoleColor.Yellow, ConsoleColor.Cyan);
Colors.Menu.Normal = MakeColor (ConsoleColor.White, ConsoleColor.Cyan);
Colors.Dialog.Normal = MakeColor (ConsoleColor.Black, ConsoleColor.Gray);
Colors.Dialog.Focus = MakeColor (ConsoleColor.Black, ConsoleColor.Cyan);
Colors.Dialog.HotNormal = MakeColor (ConsoleColor.Blue, ConsoleColor.Gray);
Colors.Dialog.HotFocus = MakeColor (ConsoleColor.Blue, ConsoleColor.Cyan);
Colors.Error.Normal = MakeColor (ConsoleColor.White, ConsoleColor.Red);
Colors.Error.Focus = MakeColor (ConsoleColor.Black, ConsoleColor.Gray);
Colors.Error.HotNormal = MakeColor (ConsoleColor.Yellow, ConsoleColor.Red);
Colors.Error.HotFocus = Colors.Error.HotNormal;
Console.Clear ();
}
void ResizeScreen ()
{
OutputBuffer = new WindowsConsole.CharInfo[Rows * Cols];
Clip = new Rect (0, 0, Cols, Rows);
}
void UpdateOffScreen ()
{
for (int row = 0; row < rows; row++)
for (int col = 0; col < cols; col++){
int position = row * cols + col;
OutputBuffer[position].Attributes = (ushort)MakeColor(ConsoleColor.White, ConsoleColor.Blue);
OutputBuffer[position].Char.UnicodeChar = ' ';
}
}
int ccol, crow;
public override void Move (int col, int row)
{
ccol = col;
crow = row;
}
public override void AddRune (Rune rune)
{
var position = crow * Cols + ccol;
if (Clip.Contains (ccol, crow)){
OutputBuffer[position].Attributes = (ushort)currentAttribute;
OutputBuffer[position].Char.UnicodeChar = (char)rune;
}
ccol++;
if (ccol == Cols) {
ccol = 0;
if (crow + 1 < Rows)
crow++;
}
if (sync)
UpdateScreen ();
}
public override void AddStr (ustring str)
{
foreach (var rune in str)
AddRune (rune);
}
int currentAttribute;
public override void SetAttribute (Attribute c)
{
currentAttribute = c.value;
}
private Attribute MakeColor (ConsoleColor f, ConsoleColor b)
{
// Encode the colors into the int value.
return new Attribute (){
value = ((int)f | (int)b << 4)
};
}
public override void Refresh()
{
var bufferCoords = new WindowsConsole.Coord (){
X = (short)Clip.Width,
Y = (short)Clip.Height
};
var window = new WindowsConsole.SmallRect (){
Top = 0,
Left = 0,
Right = (short)Clip.Right,
Bottom = (short)Clip.Bottom
};
UpdateCursor();
winConsole.WriteToConsole (OutputBuffer, bufferCoords, window);
}
public override void UpdateScreen ()
{
var bufferCoords = new WindowsConsole.Coord (){
X = (short)Clip.Width,
Y = (short)Clip.Height
};
var window = new WindowsConsole.SmallRect (){
Top = 0,
Left = 0,
Right = (short)Clip.Right,
Bottom = (short)Clip.Bottom
};
UpdateCursor();
winConsole.WriteToConsole (OutputBuffer, bufferCoords, window);
}
public override void UpdateCursor()
{
var position = new WindowsConsole.Coord(){
X = (short)ccol,
Y = (short)crow
};
winConsole.SetCursorPosition(position);
}
public override void End ()
{
winConsole.Cleanup();
}
#region Unused
public override void SetColors (ConsoleColor foreground, ConsoleColor background)
{
}
public override void SetColors (short foregroundColorId, short backgroundColorId)
{
}
public override void Suspend ()
{
}
public override void StartReportingMouseMoves ()
{
}
public override void StopReportingMouseMoves ()
{
}
public override void UncookMouse ()
{
}
public override void CookMouse ()
{
}
#endregion
}
}

View File

@@ -178,6 +178,12 @@ namespace Terminal.Gui {
/// </summary>
AltMask = 0x80000000,
/// <summary>
/// When this value is set, the Key encodes the sequence Ctrl-KeyValue.
/// And the actual value must be extracted by removing the CtrlMask.
/// </summary>
CtrlMask = 0x40000000,
/// <summary>
/// Backspace key.
/// </summary>
@@ -297,7 +303,7 @@ namespace Terminal.Gui {
public bool IsAlt => (Key & Key.AltMask) != 0;
/// <summary>
/// Determines whether the value is a control key
/// Determines whether the value is a control key (and NOT just the ctrl key)
/// </summary>
/// <value><c>true</c> if is ctrl; otherwise, <c>false</c>.</value>
public bool IsCtrl => ((uint)Key >= 1) && ((uint)Key <= 26);

View File

@@ -13,10 +13,10 @@
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -138,7 +138,7 @@ namespace Mono.Terminal {
AddWatch (wakeupPipes [0], Condition.PollIn, ml => {
read (wakeupPipes [0], ignore, (IntPtr)1);
return true;
});
});
}
/// <summary>
@@ -192,7 +192,7 @@ namespace Mono.Terminal {
}
}
bool IMainLoopDriver.EventsPending (bool wait)
bool IMainLoopDriver.EventsPending (bool wait)
{
long now = DateTime.UtcNow.Ticks;
@@ -214,10 +214,10 @@ namespace Mono.Terminal {
int ic;
lock (mainLoop.idleHandlers)
ic = mainLoop.idleHandlers.Count;
return n > 0 || mainLoop.timeouts.Count > 0 && ((mainLoop.timeouts.Keys [0] - DateTime.UtcNow.Ticks) < 0) || ic > 0;
return n > 0 || mainLoop.timeouts.Count > 0 && ((mainLoop.timeouts.Keys [0] - DateTime.UtcNow.Ticks) < 0) || ic > 0;
}
void IMainLoopDriver.MainIteration ()
void IMainLoopDriver.MainIteration ()
{
if (pollmap != null) {
foreach (var p in pollmap) {
@@ -231,7 +231,7 @@ namespace Mono.Terminal {
if (!watch.Callback (this.mainLoop))
descriptorWatchers.Remove (p.fd);
}
}
}
}
}
@@ -247,7 +247,7 @@ namespace Mono.Terminal {
public Action<ConsoleKeyInfo> WindowsKeyPressed;
MainLoop mainLoop;
public NetMainLoop ()
public NetMainLoop ()
{
}
@@ -258,16 +258,16 @@ namespace Mono.Terminal {
windowsKeyResult = Console.ReadKey (true);
keyReady.Set ();
}
}
}
void IMainLoopDriver.Setup (MainLoop mainLoop)
{
this.mainLoop = mainLoop;
Thread readThread = new Thread (WindowsKeyReader);
readThread.Start ();
readThread.Start ();
}
void IMainLoopDriver.Wakeup ()
void IMainLoopDriver.Wakeup ()
{
}
@@ -298,7 +298,7 @@ namespace Mono.Terminal {
if (WindowsKeyPressed!= null)
WindowsKeyPressed (windowsKeyResult.Value);
windowsKeyResult = null;
}
}
}
}
@@ -346,7 +346,6 @@ namespace Mono.Terminal {
action ();
return false;
});
driver.Wakeup ();
}
/// <summary>
@@ -373,7 +372,7 @@ namespace Mono.Terminal {
{
timeouts.Add ((DateTime.UtcNow + time).Ticks, timeout);
}
/// <summary>
/// Adds a timeout to the mainloop.
/// </summary>
@@ -440,9 +439,9 @@ namespace Mono.Terminal {
idleHandlers.Add (idle);
}
}
bool running;
/// <summary>
/// Stops the mainloop.
/// </summary>
@@ -458,7 +457,7 @@ namespace Mono.Terminal {
/// <remarks>
/// You can use this method if you want to probe if events are pending.
/// Typically used if you need to flush the input queue while still
/// running some of your own code in your main thread.
/// running some of your own code in your main thread.
/// </remarks>
public bool EventsPending (bool wait = false)
{
@@ -486,7 +485,7 @@ namespace Mono.Terminal {
RunIdle();
}
}
/// <summary>
/// Runs the mainloop.
/// </summary>

View File

@@ -44,8 +44,22 @@ namespace Terminal.Gui {
{
var cFrame = new Rect (1, 1 , frame.Width - 2, frame.Height - 2);
contentView = new ContentView (cFrame);
base.Add (contentView);
Title = title;
Initialize ();
}
/// <summary>
/// Initializes a new instance of the <see cref="T:Terminal.Gui.Gui.FrameView"/> class with
/// an absolute position, a title and views.
/// </summary>
/// <param name="frame">Frame.</param>
/// <param name="title">Title.</param>
/// /// <param name="views">Views.</param>
public FrameView (Rect frame, ustring title, View[] views) : this (frame, title)
{
foreach (var view in views) {
contentView.Add (view);
}
Initialize ();
}
/// <summary>
@@ -61,11 +75,15 @@ namespace Terminal.Gui {
Width = Dim.Fill (2),
Height = Dim.Fill (2)
};
Initialize ();
}
void Initialize ()
{
base.Add (contentView);
Title = title;
}
void DrawFrame ()
{
DrawFrame (new Rect (0, 0, Frame.Width, Frame.Height), 0, fill: true);

File diff suppressed because it is too large Load Diff

View File

@@ -114,21 +114,19 @@ namespace Terminal.Gui {
var by1 = position * bh / Size;
var by2 = (position + bh) * bh / Size;
Move (col, 0);
Driver.AddRune ('^');
Move (col, Bounds.Height - 1);
Driver.AddRune ('v');
for (int y = 0; y < bh; y++) {
Move (col, y+1);
if (y < by1 || y > by2)
if (y < by1 - 1 || y > by2)
special = Driver.Stipple;
else {
if (by2 - by1 == 0)
if (by2 - by1 == 0 && by1 < bh - 1)
special = Driver.Diamond;
else {
if (y == by1)
if (y == by1 - 1)
special = Driver.TopTee;
else if (y == by2)
special = Driver.BottomTee;
@@ -192,7 +190,8 @@ namespace Terminal.Gui {
public override bool MouseEvent(MouseEvent me)
{
if (me.Flags != MouseFlags.Button1Clicked)
if (me.Flags != MouseFlags.Button1Pressed && me.Flags != MouseFlags.Button1Clicked &&
!me.Flags.HasFlag (MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition))
return false;
int location = vertical ? me.Y : me.X;
@@ -208,11 +207,23 @@ namespace Terminal.Gui {
if (location == 0) {
if (pos > 0)
SetPosition (pos - 1);
} else if (location == barsize + 1){
} else if (location == barsize + 1) {
if (pos + 1 + barsize < Size)
SetPosition (pos + 1);
} else {
Console.WriteLine ("TODO at ScrollBarView");
var b1 = pos * barsize / Size;
var b2 = (pos + barsize) * barsize / Size;
if (b2 == 0 && location == 1 && pos == 0 ||
(b2 == barsize && location == barsize) ||
(location > b1 && location < b2)) {
return true;
} else if (location <= barsize) {
if (location > 1 && location >= b2)
SetPosition (Math.Min (pos + barsize, Size));
else if (location <= b2 && pos > 0 || pos > 0)
SetPosition (Math.Max (pos - barsize, 0));
}
}
}
@@ -309,7 +320,7 @@ namespace Terminal.Gui {
set {
if (value == showHorizontalScrollIndicator)
return;
showHorizontalScrollIndicator = value;
SetNeedsDisplay ();
if (value)
@@ -338,7 +349,7 @@ namespace Terminal.Gui {
set {
if (value == showVerticalScrollIndicator)
return;
showVerticalScrollIndicator = value;
SetNeedsDisplay ();
if (value)
@@ -431,7 +442,7 @@ namespace Terminal.Gui {
var nx = Math.Max (-contentSize.Width, contentOffset.X - cols);
if (nx == contentOffset.X)
return false;
ContentOffset = new Point (nx, contentOffset.Y);
return true;
}
@@ -461,6 +472,12 @@ namespace Terminal.Gui {
case Key.CursorRight:
return ScrollRight (1);
case Key.Home:
return ScrollUp (contentSize.Height);
case Key.End:
return ScrollDown (contentSize.Height);
}
return false;
}

View File

@@ -6,27 +6,24 @@
//
// TODO:
// Add mouse support
// Uses internals of Application
using System;
using NStack;
namespace Terminal.Gui
{
namespace Terminal.Gui {
/// <summary>
/// A statusbar item has a title, a shortcut aka hotkey, and an action to execute on activation.
/// Such an item is ment to be as part of the global hotkeys of the application, which are available in the current context of the screen.
/// The colour of the text will be changed after each ~. Having an statusbar item with a text of `~F1~ Help` will draw *F1* as shortcut and
/// The colour of the text will be changed after each ~. Having an statusbar item with a text of `~F1~ Help` will draw *F1* as shortcut and
/// *Help* as standard text.
/// </summary>
public class StatusItem
{
public class StatusItem {
/// <summary>
/// Initializes a new <see cref="T:Terminal.Gui.StatusItem"/>.
/// </summary>
/// <param name="shortcut">Shortcut to activate the item.</param>
/// <param name="title">Title for the statusbar item.</param>
/// <param name="action">Action to invoke when the staturbar item is activated.</param>
public StatusItem(Key shortcut, ustring title, Action action)
public StatusItem (Key shortcut, ustring title, Action action)
{
Title = title ?? "";
Shortcut = shortcut;
@@ -52,39 +49,91 @@ namespace Terminal.Gui
};
/// <summary>
/// A statusbar for your application.
/// A statusbar for your application.
/// The statusbar should be context sensitive. This means, if the main menu and an open text editor are visible, the items probably shown will
/// be ~F1~ Help ~F2~ Save ~F3~ Load. While a dialog to ask a file to load is executed, the remaining commands will probably be ~F1~ Help.
/// So for each context must be a new instance of a statusbar.
/// be ~F1~ Help ~F2~ Save ~F3~ Load. While a dialog to ask a file to load is executed, the remaining commands will probably be ~F1~ Help.
/// So for each context must be a new instance of a statusbar.
/// </summary>
public class StatusBar : View
{
public class StatusBar : View {
// After attempting to implement this, I noticed that there are hard dependencies
// on StatusBar and MenuBars within core. They will need to be refactored for having the
// StatusBar work at the top
#if SNAP_TO_TOP
/// <summary>
/// The style supported by StatusBar
/// </summary>
public enum StatusBarStyle {
Default = 0,
/// <summary>
/// The StatusBar will snap at the the bottom line of the Parent view.
/// If the console window is made larger while the app is runing, the StatusBar
/// will continue to snap to the bottom line of the Parent, staying visible.
/// On consoles that support resizing of console apps (e.g. Windows Terminal and ConEmu),
/// if the console window is subsequently made shorter, the status bar will remain visible
/// as the Parent view resizes. If Parent is null, the StatusBar will snap to the bottom line
/// of the console window.
/// This is the default.
/// </summary>
SnapToBottom = Default,
/// <summary>
/// The StatusBar will act identically to MenuBar, snapping to the first line of the
/// console window.
/// </summary>
SnapToTop = 1,
}
public StatusBarStyle Style { get; set; } = StatusBarStyle.Default;
#endif
public View Parent { get; set; }
public StatusItem [] Items { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="T:Terminal.Gui.StatusBar"/> class with the specified set of statusbar items.
/// It will be drawn in the lowest column of the terminal.
/// It will be drawn in the lowest line of the terminal.
/// </summary>
/// <param name="items">A list of statusbar items.</param>
public StatusBar(StatusItem [] items) : base()
public StatusBar (StatusItem [] items) : base ()
{
X = 0;
Y = Application.Driver.Rows - 1; // TODO: using internals of Application
Width = Dim.Fill ();
Height = 1;
Items = items;
CanFocus = false;
ColorScheme = Colors.Menu;
Application.OnLoad += () => {
X = 0;
Height = 1;
#if SNAP_TO_TOP
switch (Style) {
case StatusBarStyle.SnapToTop:
X = 0;
Y = 0;
break;
case StatusBarStyle.SnapToBottom:
#endif
if (Parent == null) {
Y = Application.Driver.Rows - 1; // TODO: using internals of Application
} else {
Y = Pos.Bottom (Parent);
}
#if SNAP_TO_TOP
break;
}
#endif
};
}
Attribute ToggleScheme(Attribute scheme)
Attribute ToggleScheme (Attribute scheme)
{
var result = scheme==ColorScheme.Normal ? ColorScheme.HotNormal : ColorScheme.Normal;
Driver.SetAttribute(result);
var result = scheme == ColorScheme.Normal ? ColorScheme.HotNormal : ColorScheme.Normal;
Driver.SetAttribute (result);
return result;
}
public override void Redraw(Rect region) {
public override void Redraw (Rect region)
{
if (Frame.Y != Driver.Rows - 1) {
Frame = new Rect (Frame.X, Driver.Rows - 1, Frame.Width, Frame.Height);
Y = Driver.Rows - 1;
@@ -98,15 +147,15 @@ namespace Terminal.Gui
Move (1, 0);
var scheme = ColorScheme.Normal;
Driver.SetAttribute(scheme);
for(int i=0; i<Items.Length; i++) {
var title = Items[i].Title;
for(int n=0; n<title.Length; n++) {
if(title[n]=='~') {
scheme = ToggleScheme(scheme);
Driver.SetAttribute (scheme);
for (int i = 0; i < Items.Length; i++) {
var title = Items [i].Title;
for (int n = 0; n < title.Length; n++) {
if (title [n] == '~') {
scheme = ToggleScheme (scheme);
continue;
}
Driver.AddRune(title[n]);
Driver.AddRune (title [n]);
}
Driver.AddRune (' ');
}
@@ -114,9 +163,9 @@ namespace Terminal.Gui
public override bool ProcessHotKey (KeyEvent kb)
{
foreach(var item in Items) {
if(kb.Key==item.Shortcut) {
if( item.Action!=null ) item.Action();
foreach (var item in Items) {
if (kb.Key == item.Shortcut) {
if (item.Action != null) item.Action ();
return true;
}
}

View File

@@ -43,7 +43,7 @@ namespace Terminal.Gui {
/// <param name="text">Initial text contents.</param>
public TextField (string text) : this (ustring.Make (text))
{
Height = 1;
}
/// <summary>
@@ -85,6 +85,8 @@ namespace Terminal.Gui {
{
if (Application.mouseGrabView != null && Application.mouseGrabView == this)
Application.UngrabMouse ();
if (SelectedLength != 0 && !(Application.mouseGrabView is MenuBar))
ClearAllSelection ();
}
public override Rect Frame {
@@ -473,18 +475,17 @@ namespace Terminal.Gui {
public override bool MouseEvent (MouseEvent ev)
{
if (!ev.Flags.HasFlag (MouseFlags.Button1Clicked) && !ev.Flags.HasFlag (MouseFlags.Button1Pressed) &&
!ev.Flags.HasFlag (MouseFlags.ReportMousePosition))
if (!ev.Flags.HasFlag (MouseFlags.Button1Pressed) && !ev.Flags.HasFlag (MouseFlags.ReportMousePosition) &&
!ev.Flags.HasFlag (MouseFlags.Button1Released))
return false;
if (ev.Flags == MouseFlags.Button1Clicked) {
if (ev.Flags == MouseFlags.Button1Pressed) {
if (!HasFocus)
SuperView.SetFocus (this);
int x = PositionCursor (ev);
PositionCursor (ev);
if (isButtonReleased)
ClearAllSelection ();
isButtonReleased = true;
Application.UngrabMouse ();
} else if (ev.Flags == (MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition)) {
int x = PositionCursor (ev);
isButtonReleased = false;
@@ -496,6 +497,9 @@ namespace Terminal.Gui {
int x = PositionCursor (ev);
if (SelectedLength != 0)
ClearAllSelection ();
} else if (ev.Flags == MouseFlags.Button1Released) {
isButtonReleased = true;
Application.UngrabMouse ();
}
SetNeedsDisplay ();

View File

@@ -1,59 +1,59 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example", "Example\Example.csproj", "{B0A602CD-E176-449D-8663-64238D54F857}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Terminal.Gui", "Terminal.Gui\Terminal.Gui.csproj", "{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Designer", "Designer\Designer.csproj", "{1228D992-C801-49BB-839A-7BD28A3FFF0A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B0A602CD-E176-449D-8663-64238D54F857}.Debug|x86.ActiveCfg = Debug|x86
{B0A602CD-E176-449D-8663-64238D54F857}.Debug|x86.Build.0 = Debug|x86
{B0A602CD-E176-449D-8663-64238D54F857}.Release|x86.ActiveCfg = Release|x86
{B0A602CD-E176-449D-8663-64238D54F857}.Release|x86.Build.0 = Release|x86
{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Debug|x86.ActiveCfg = Debug|Any CPU
{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Debug|x86.Build.0 = Debug|Any CPU
{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Release|x86.ActiveCfg = Release|Any CPU
{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Release|x86.Build.0 = Release|Any CPU
{1228D992-C801-49BB-839A-7BD28A3FFF0A}.Debug|x86.ActiveCfg = Debug|x86
{1228D992-C801-49BB-839A-7BD28A3FFF0A}.Debug|x86.Build.0 = Debug|x86
{1228D992-C801-49BB-839A-7BD28A3FFF0A}.Release|x86.ActiveCfg = Release|x86
{1228D992-C801-49BB-839A-7BD28A3FFF0A}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
Policies = $0
$0.TextStylePolicy = $1
$1.FileWidth = 80
$1.scope = text/x-csharp
$1.TabWidth = 8
$1.IndentWidth = 8
$0.CSharpFormattingPolicy = $2
$2.scope = text/x-csharp
$2.IndentSwitchSection = False
$2.NewLinesForBracesInTypes = False
$2.NewLinesForBracesInProperties = False
$2.NewLinesForBracesInAccessors = False
$2.NewLinesForBracesInAnonymousMethods = False
$2.NewLinesForBracesInControlBlocks = False
$2.NewLinesForBracesInAnonymousTypes = False
$2.NewLinesForBracesInObjectCollectionArrayInitializers = False
$2.NewLinesForBracesInLambdaExpressionBody = False
$2.NewLineForElse = False
$2.NewLineForCatch = False
$2.NewLineForFinally = False
$2.NewLineForMembersInObjectInit = False
$2.NewLineForMembersInAnonymousTypes = False
$2.NewLineForClausesInQuery = False
$2.SpacingAfterMethodDeclarationName = True
$2.SpaceAfterMethodCallName = True
$2.SpaceBeforeOpenSquareBracket = True
$0.DotNetNamingPolicy = $3
$0.StandardHeader = $4
EndGlobalSection
EndGlobal
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example", "Example\Example.csproj", "{B0A602CD-E176-449D-8663-64238D54F857}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Terminal.Gui", "Terminal.Gui\Terminal.Gui.csproj", "{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Designer", "Designer\Designer.csproj", "{1228D992-C801-49BB-839A-7BD28A3FFF0A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B0A602CD-E176-449D-8663-64238D54F857}.Debug|x86.ActiveCfg = Debug|x86
{B0A602CD-E176-449D-8663-64238D54F857}.Debug|x86.Build.0 = Debug|x86
{B0A602CD-E176-449D-8663-64238D54F857}.Release|x86.ActiveCfg = Release|x86
{B0A602CD-E176-449D-8663-64238D54F857}.Release|x86.Build.0 = Release|x86
{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Debug|x86.ActiveCfg = Debug|Any CPU
{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Debug|x86.Build.0 = Debug|Any CPU
{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Release|x86.ActiveCfg = Release|Any CPU
{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Release|x86.Build.0 = Release|Any CPU
{1228D992-C801-49BB-839A-7BD28A3FFF0A}.Debug|x86.ActiveCfg = Debug|x86
{1228D992-C801-49BB-839A-7BD28A3FFF0A}.Debug|x86.Build.0 = Debug|x86
{1228D992-C801-49BB-839A-7BD28A3FFF0A}.Release|x86.ActiveCfg = Release|x86
{1228D992-C801-49BB-839A-7BD28A3FFF0A}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
Policies = $0
$0.TextStylePolicy = $1
$1.FileWidth = 80
$1.scope = text/x-csharp
$1.TabWidth = 8
$1.IndentWidth = 8
$0.CSharpFormattingPolicy = $2
$2.scope = text/x-csharp
$2.IndentSwitchSection = False
$2.NewLinesForBracesInTypes = False
$2.NewLinesForBracesInProperties = False
$2.NewLinesForBracesInAccessors = False
$2.NewLinesForBracesInAnonymousMethods = False
$2.NewLinesForBracesInControlBlocks = False
$2.NewLinesForBracesInAnonymousTypes = False
$2.NewLinesForBracesInObjectCollectionArrayInitializers = False
$2.NewLinesForBracesInLambdaExpressionBody = False
$2.NewLineForElse = False
$2.NewLineForCatch = False
$2.NewLineForFinally = False
$2.NewLineForMembersInObjectInit = False
$2.NewLineForMembersInAnonymousTypes = False
$2.NewLineForClausesInQuery = False
$2.SpacingAfterMethodDeclarationName = True
$2.SpaceAfterMethodCallName = True
$2.SpaceBeforeOpenSquareBracket = True
$0.DotNetNamingPolicy = $3
$0.StandardHeader = $4
EndGlobalSection
EndGlobal