mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2026-01-01 16:59:35 +01:00
Added more mouse events flags, drag features, toplevel color and more...
This commit is contained in:
@@ -228,7 +228,15 @@ namespace Terminal.Gui {
|
||||
View container = null;
|
||||
View focused = null;
|
||||
Direction focusDirection;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when the view get focus.
|
||||
/// </summary>
|
||||
public event EventHandler OnEnter;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when the view lost focus.
|
||||
/// </summary>
|
||||
public event EventHandler OnLeave;
|
||||
|
||||
internal Direction FocusDirection {
|
||||
@@ -441,7 +449,7 @@ namespace Terminal.Gui {
|
||||
layoutNeeded = true;
|
||||
if (SuperView == null)
|
||||
return;
|
||||
SuperView.layoutNeeded = true;
|
||||
SuperView.SetNeedsLayout ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -657,58 +665,13 @@ namespace Terminal.Gui {
|
||||
{
|
||||
var h = r.Height;
|
||||
var w = r.Width;
|
||||
for (int line = 0; line < h; line++) {
|
||||
Move (0, line);
|
||||
for (int line = r.Y; line < r.Y + h; line++) {
|
||||
Driver.Move (r.X, line);
|
||||
for (int col = 0; col < w; col++)
|
||||
Driver.AddRune (' ');
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the specified rectangular region with the container color
|
||||
/// </summary>
|
||||
public void ClearContainer (Rect r)
|
||||
{
|
||||
if (this.container != null) {
|
||||
var current = ColorScheme;
|
||||
switch (this.container.ColorScheme.Caller) {
|
||||
case "Base":
|
||||
Driver.SetAttribute (Colors.Base.Normal);
|
||||
break;
|
||||
case "Dialog":
|
||||
Driver.SetAttribute (Colors.Dialog.Normal);
|
||||
break;
|
||||
case "Error":
|
||||
Driver.SetAttribute (Colors.Error.Normal);
|
||||
break;
|
||||
case "Menu":
|
||||
Driver.SetAttribute (Colors.Menu.Normal);
|
||||
break;
|
||||
}
|
||||
var h = r.Height;
|
||||
var w = r.Width;
|
||||
for (int line = r.Y; line < r.Y + h; line++) {
|
||||
Driver.Move (r.X, line);
|
||||
for (int col = 0; col < w; col++)
|
||||
Driver.AddRune (' ');
|
||||
}
|
||||
ColorScheme = current;
|
||||
}
|
||||
}
|
||||
|
||||
public void GrabToView (MouseEvent mouseEvent, int startX, Point? dragPos, Rect frame, out int nx, out int ny)
|
||||
{
|
||||
var dx = mouseEvent.X - dragPos.Value.X - startX + frame.Left;
|
||||
var dy = mouseEvent.Y - dragPos.Value.Y;
|
||||
|
||||
nx = dx;
|
||||
ny = frame.Y + dy;
|
||||
if (nx < 0)
|
||||
nx = 0;
|
||||
if (ny < 1)
|
||||
ny = frame.Y;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the (col,row) position from the view into a screen (col,row). The values are clamped to (0..ScreenDim-1)
|
||||
/// </summary>
|
||||
@@ -971,7 +934,9 @@ namespace Terminal.Gui {
|
||||
if (!view.NeedDisplay.IsEmpty || view.childNeedsDisplay) {
|
||||
if (view.Frame.IntersectsWith (clipRect) && view.Frame.IntersectsWith (region)) {
|
||||
|
||||
// TODO: optimize this by computing the intersection of region and view.Bounds
|
||||
// FIXED: optimize this by computing the intersection of region and view.Bounds
|
||||
if (view.layoutNeeded)
|
||||
view.LayoutSubviews ();
|
||||
view.Redraw (view.Bounds);
|
||||
}
|
||||
view.NeedDisplay = Rect.Empty;
|
||||
@@ -1362,7 +1327,7 @@ namespace Terminal.Gui {
|
||||
/// <param name="frame">Frame.</param>
|
||||
public Toplevel (Rect frame) : base (frame)
|
||||
{
|
||||
ColorScheme = Colors.Base;
|
||||
Initialize ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1370,11 +1335,16 @@ namespace Terminal.Gui {
|
||||
/// </summary>
|
||||
public Toplevel () : base ()
|
||||
{
|
||||
ColorScheme = Colors.Base;
|
||||
Initialize ();
|
||||
Width = Dim.Fill ();
|
||||
Height = Dim.Fill ();
|
||||
}
|
||||
|
||||
void Initialize ()
|
||||
{
|
||||
ColorScheme = Colors.Base;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convenience factory method that creates a new toplevel with the current terminal dimensions.
|
||||
/// </summary>
|
||||
@@ -1395,6 +1365,16 @@ namespace Terminal.Gui {
|
||||
/// </summary>
|
||||
public bool Modal { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Check id current toplevel has menu bar
|
||||
/// </summary>
|
||||
public bool HasMenuBar { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Check id current toplevel has status bar
|
||||
/// </summary>
|
||||
public bool HasStatusBar { get; set; }
|
||||
|
||||
public override bool ProcessKey (KeyEvent keyEvent)
|
||||
{
|
||||
if (base.ProcessKey (keyEvent))
|
||||
@@ -1444,6 +1424,100 @@ namespace Terminal.Gui {
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void Add (View view)
|
||||
{
|
||||
if (this == Application.Top) {
|
||||
if (view is MenuBar)
|
||||
HasMenuBar = true;
|
||||
if (view is StatusBar)
|
||||
HasStatusBar = true;
|
||||
}
|
||||
base.Add (view);
|
||||
}
|
||||
|
||||
public override void Remove (View view)
|
||||
{
|
||||
if (this == Application.Top) {
|
||||
if (view is MenuBar)
|
||||
HasMenuBar = true;
|
||||
if (view is StatusBar)
|
||||
HasStatusBar = true;
|
||||
}
|
||||
base.Remove (view);
|
||||
}
|
||||
|
||||
public override void RemoveAll ()
|
||||
{
|
||||
if (this == Application.Top) {
|
||||
HasMenuBar = false;
|
||||
HasStatusBar = false;
|
||||
}
|
||||
base.RemoveAll ();
|
||||
}
|
||||
|
||||
internal void EnsureVisibleBounds (Toplevel top, int x, int y, out int nx, out int ny)
|
||||
{
|
||||
nx = Math.Max (x, 0);
|
||||
nx = nx + top.Frame.Width > Driver.Cols ? Math.Max(Driver.Cols - top.Frame.Width, 0) : nx;
|
||||
bool m, s;
|
||||
if (SuperView == null)
|
||||
m = Application.Top.HasMenuBar;
|
||||
else
|
||||
m = ((Toplevel)SuperView).HasMenuBar;
|
||||
int l = m ? 1 : 0;
|
||||
ny = Math.Max (y, l);
|
||||
if (SuperView == null)
|
||||
s = Application.Top.HasStatusBar;
|
||||
else
|
||||
s = ((Toplevel)SuperView).HasStatusBar;
|
||||
l = s ? Driver.Rows - 1 : Driver.Rows;
|
||||
ny = Math.Min (ny, l);
|
||||
ny = ny + top.Frame.Height > l ? Math.Max(l - top.Frame.Height, m ? 1 : 0) : ny;
|
||||
}
|
||||
|
||||
//Dictionary<View, Rect> subViews;
|
||||
internal void PositionToplevels ()
|
||||
{
|
||||
if (this != Application.Top) {
|
||||
EnsureVisibleBounds (this, Frame.X, Frame.Y, out int nx, out int ny);
|
||||
if (nx != Frame.X || ny != Frame.Y) {
|
||||
X = nx;
|
||||
Y = ny;
|
||||
}
|
||||
} else {
|
||||
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) {
|
||||
top.X = nx;
|
||||
top.Y = ny;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Redraw (Rect region)
|
||||
{
|
||||
if (this == Application.Top) {
|
||||
if (!NeedDisplay.IsEmpty) {
|
||||
Driver.SetAttribute (Colors.TopLevel.Normal);
|
||||
Clear (region);
|
||||
Driver.SetAttribute (Colors.Base.Normal);
|
||||
}
|
||||
foreach (var view in Subviews) {
|
||||
if (view.Frame.IntersectsWith (region)) {
|
||||
//view.SetNeedsLayout ();
|
||||
view.SetNeedsDisplay (view.Bounds);
|
||||
}
|
||||
}
|
||||
|
||||
ClearNeedsDisplay ();
|
||||
}
|
||||
|
||||
base.Redraw (base.Bounds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is invoked by Application.Begin as part of the Application.Run after
|
||||
/// the views have been laid out, and before the views are drawn for the first time.
|
||||
@@ -1628,73 +1702,58 @@ namespace Terminal.Gui {
|
||||
// FIXED:It does not look like the event is raised on clicked-drag
|
||||
// need to figure that out.
|
||||
//
|
||||
Point? dragPosition;
|
||||
int startX;
|
||||
public override bool MouseEvent(MouseEvent mouseEvent)
|
||||
internal static Point? dragPosition;
|
||||
Point start;
|
||||
public override bool MouseEvent (MouseEvent mouseEvent)
|
||||
{
|
||||
// FIXED:The code is currently disabled, because the
|
||||
// Driver.UncookMouse does not seem to have an effect if there is
|
||||
// a pending mouse event activated.
|
||||
|
||||
if ((mouseEvent.Flags == (MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition) ||
|
||||
int nx, ny;
|
||||
if ((mouseEvent.Flags == (MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition) ||
|
||||
mouseEvent.Flags == MouseFlags.Button4Pressed)) {
|
||||
|
||||
if (dragPosition.HasValue) {
|
||||
int nx, ny;
|
||||
GrabToView (mouseEvent, startX, dragPosition, Frame, out nx, out ny);
|
||||
dragPosition = new Point (nx, ny);
|
||||
if (SuperView == null) {
|
||||
Application.Top.SetNeedsDisplay (Frame);
|
||||
Application.Top.Redraw (Frame);
|
||||
} else {
|
||||
SuperView.SetNeedsDisplay (Frame);
|
||||
}
|
||||
EnsureVisibleBounds (this, mouseEvent.X + mouseEvent.OfX - start.X,
|
||||
mouseEvent.Y + mouseEvent.OfY, out nx, out ny);
|
||||
|
||||
//System.Diagnostics.Debug.WriteLine ($"dragging: {mouseEvent}");
|
||||
//System.Diagnostics.Debug.WriteLine ($"dx: {dx}, dy: {dy}");
|
||||
//System.Diagnostics.Debug.WriteLine ($"nx: {nx}, ny: {ny}");
|
||||
dragPosition = new Point (nx, ny);
|
||||
Frame = new Rect (nx, ny, Frame.Width, Frame.Height);
|
||||
X = nx;
|
||||
Y = ny;
|
||||
//Demo.ml2.Text = $"{dx},{dy}";
|
||||
|
||||
// TODO: optimize, only SetNeedsDisplay on the before/after regions.
|
||||
if (SuperView == null)
|
||||
Application.Refresh ();
|
||||
else
|
||||
SuperView.SetNeedsDisplay ();
|
||||
|
||||
Frame = new Rect (nx, ny, Frame.Width, Frame.Height);
|
||||
Rect top = new Rect () {
|
||||
X = 0,
|
||||
Y = 0,
|
||||
Width = Driver.Cols,
|
||||
Height = ny
|
||||
};
|
||||
Rect left = new Rect () {
|
||||
X = 0,
|
||||
Y = ny,
|
||||
Width = nx,
|
||||
Height = Driver.Rows
|
||||
};
|
||||
ClearContainer (top);
|
||||
ClearContainer (left);
|
||||
// FIXED: optimize, only SetNeedsDisplay on the before/after regions.
|
||||
SetNeedsDisplay ();
|
||||
return true;
|
||||
} else {
|
||||
// Only start grabbing if the user clicks on the title bar.
|
||||
if (mouseEvent.Y == 0) {
|
||||
startX = mouseEvent.X;
|
||||
dragPosition = new Point (mouseEvent.X, mouseEvent.Y);
|
||||
start = new Point (mouseEvent.X, mouseEvent.Y);
|
||||
dragPosition = new Point ();
|
||||
nx = mouseEvent.X - mouseEvent.OfX;
|
||||
ny = mouseEvent.Y - mouseEvent.OfY;
|
||||
dragPosition = new Point (nx, ny);
|
||||
Application.GrabMouse (this);
|
||||
}
|
||||
|
||||
//System.Diagnostics.Debug.WriteLine ($"Starting at {dragPosition}");
|
||||
//Demo.ml2.Text = $"Starting at {dragPosition}";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (mouseEvent.Flags == MouseFlags.Button1Released) {
|
||||
if (mouseEvent.Flags == MouseFlags.Button1Released && dragPosition.HasValue) {
|
||||
Application.UngrabMouse ();
|
||||
Driver.UncookMouse ();
|
||||
|
||||
dragPosition = null;
|
||||
//Driver.StopReportingMouseMoves ();
|
||||
}
|
||||
|
||||
//System.Diagnostics.Debug.WriteLine ($"mouseEvent {mouseEvent.ToString ()}");
|
||||
//Demo.ml.Text = me.ToString ();
|
||||
return false;
|
||||
}
|
||||
@@ -1784,9 +1843,9 @@ namespace Terminal.Gui {
|
||||
{
|
||||
mainLoop.AddIdle (() => {
|
||||
d (state);
|
||||
mainLoop.Driver.Wakeup ();
|
||||
return false;
|
||||
});
|
||||
mainLoop.Driver.Wakeup ();
|
||||
}
|
||||
|
||||
public override void Send (SendOrPostCallback d, object state)
|
||||
@@ -1902,7 +1961,7 @@ namespace Terminal.Gui {
|
||||
}
|
||||
}
|
||||
|
||||
internal static View FindDeepestView (View start, int x, int y, out int resx, out int resy)
|
||||
static View FindDeepestView (View start, int x, int y, out int resx, out int resy)
|
||||
{
|
||||
var startFrame = start.Frame;
|
||||
|
||||
@@ -1933,7 +1992,7 @@ namespace Terminal.Gui {
|
||||
return start;
|
||||
}
|
||||
|
||||
static View mouseGrabView;
|
||||
internal static View mouseGrabView;
|
||||
|
||||
/// <summary>
|
||||
/// Grabs the mouse, forcing all mouse events to be routed to the specified view until UngrabMouse is called.
|
||||
@@ -1964,20 +2023,22 @@ namespace Terminal.Gui {
|
||||
|
||||
static void ProcessMouseEvent (MouseEvent me)
|
||||
{
|
||||
var view = FindDeepestView (Current, me.X, me.Y, out int rx, out int ry);
|
||||
RootMouseEvent?.Invoke (me);
|
||||
if (mouseGrabView != null) {
|
||||
var newxy = mouseGrabView.ScreenToView (me.X, me.Y);
|
||||
var nme = new MouseEvent () {
|
||||
X = newxy.X,
|
||||
Y = newxy.Y,
|
||||
Flags = me.Flags
|
||||
Flags = me.Flags,
|
||||
OfX = me.X - newxy.X,
|
||||
OfY = me.Y - newxy.Y,
|
||||
View = view
|
||||
};
|
||||
mouseGrabView.MouseEvent (me);
|
||||
mouseGrabView.MouseEvent (nme);
|
||||
return;
|
||||
}
|
||||
|
||||
int rx, ry;
|
||||
var view = FindDeepestView (Current, me.X, me.Y, out rx, out ry);
|
||||
if (view != null) {
|
||||
if (!view.WantMousePositionReports && me.Flags == MouseFlags.ReportMousePosition)
|
||||
return;
|
||||
@@ -1985,7 +2046,10 @@ namespace Terminal.Gui {
|
||||
var nme = new MouseEvent () {
|
||||
X = rx,
|
||||
Y = ry,
|
||||
Flags = me.Flags
|
||||
Flags = me.Flags,
|
||||
OfX = rx,
|
||||
OfY = ry,
|
||||
View = view
|
||||
};
|
||||
// Should we bubbled up the event, if it is not handled?
|
||||
view.MouseEvent (nme);
|
||||
@@ -2035,7 +2099,7 @@ namespace Terminal.Gui {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Building block API: completes the exection of a Toplevel that was started with Begin.
|
||||
/// Building block API: completes the execution of a Toplevel that was started with Begin.
|
||||
/// </summary>
|
||||
/// <param name="runState">The runstate returned by the <see cref="Begin(Toplevel)"/> method.</param>
|
||||
static public void End (RunState runState)
|
||||
@@ -2046,6 +2110,9 @@ namespace Terminal.Gui {
|
||||
runState.Dispose ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finalize the driver.
|
||||
/// </summary>
|
||||
public static void Shutdown ()
|
||||
{
|
||||
Driver.End ();
|
||||
@@ -2122,40 +2189,11 @@ namespace Terminal.Gui {
|
||||
DrawBounds (state.Toplevel);
|
||||
state.Toplevel.PositionCursor ();
|
||||
Driver.Refresh ();
|
||||
} else if (CheckLayoutNeeded (state.Toplevel)) {
|
||||
TerminalResized ();
|
||||
layoutNeeded = false;
|
||||
toplevel = null;
|
||||
} else
|
||||
Driver.UpdateCursor ();
|
||||
}
|
||||
}
|
||||
|
||||
static bool layoutNeeded;
|
||||
static View toplevel;
|
||||
static bool CheckLayoutNeeded (View view)
|
||||
{
|
||||
if (view is Toplevel && ((Toplevel)view).Modal)
|
||||
return false;
|
||||
if (view is Toplevel)
|
||||
toplevel = view;
|
||||
|
||||
return CheckTopLevelLayoutNeeded (view);
|
||||
}
|
||||
|
||||
private static bool CheckTopLevelLayoutNeeded (View view)
|
||||
{
|
||||
if (!(view is Toplevel) && view == toplevel && view.layoutNeeded)
|
||||
return layoutNeeded = view.layoutNeeded;
|
||||
|
||||
for (int i = 0; view.Subviews.Count > i; i++) {
|
||||
CheckLayoutNeeded (view.Subviews [i]);
|
||||
if (layoutNeeded)
|
||||
return layoutNeeded;
|
||||
}
|
||||
return layoutNeeded;
|
||||
}
|
||||
|
||||
internal static bool DebugDrawBounds;
|
||||
|
||||
// Need to look into why this does not work properly.
|
||||
@@ -2229,6 +2267,7 @@ namespace Terminal.Gui {
|
||||
var full = new Rect (0, 0, Driver.Cols, Driver.Rows);
|
||||
Driver.Clip = full;
|
||||
foreach (var t in toplevels) {
|
||||
t.PositionToplevels ();
|
||||
t.RelativeLayout (full);
|
||||
t.LayoutSubviews ();
|
||||
}
|
||||
|
||||
@@ -110,6 +110,11 @@ namespace Terminal.Gui {
|
||||
this.background = background;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:Terminal.Gui.Attribute"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="foreground">Foreground</param>
|
||||
/// <param name="background">Background</param>
|
||||
public Attribute (Color foreground = new Color (), Color background = new Color ())
|
||||
{
|
||||
this.value = value = ((int)foreground | (int)background << 4);
|
||||
@@ -156,6 +161,7 @@ namespace Terminal.Gui {
|
||||
private Attribute _hotNormal;
|
||||
private Attribute _hotFocus;
|
||||
private Attribute _disabled;
|
||||
internal string caller = "";
|
||||
|
||||
/// <summary>
|
||||
/// The default color for text, when the view is not focused.
|
||||
@@ -182,8 +188,6 @@ namespace Terminal.Gui {
|
||||
/// </summary>
|
||||
public Attribute Disabled { get { return _disabled; } set { _disabled = SetAttribute (value); } }
|
||||
|
||||
public string Caller = "";
|
||||
|
||||
private bool preparingScheme = false;
|
||||
|
||||
private Attribute SetAttribute (Attribute attribute, [CallerMemberName]string callerMemberName = null)
|
||||
@@ -195,7 +199,26 @@ namespace Terminal.Gui {
|
||||
return attribute;
|
||||
|
||||
preparingScheme = true;
|
||||
switch (Caller) {
|
||||
switch (caller) {
|
||||
case "TopLevel":
|
||||
switch (callerMemberName) {
|
||||
case "Normal":
|
||||
HotNormal = Application.Driver.MakeAttribute (HotNormal.foreground, attribute.background);
|
||||
break;
|
||||
case "Focus":
|
||||
HotFocus = Application.Driver.MakeAttribute (HotFocus.foreground, attribute.background);
|
||||
break;
|
||||
case "HotNormal":
|
||||
HotFocus = Application.Driver.MakeAttribute (attribute.foreground, HotFocus.background);
|
||||
break;
|
||||
case "HotFocus":
|
||||
HotNormal = Application.Driver.MakeAttribute (attribute.foreground, HotNormal.background);
|
||||
if (Focus.foreground != attribute.background)
|
||||
Focus = Application.Driver.MakeAttribute (Focus.foreground, attribute.background);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case "Base":
|
||||
switch (callerMemberName) {
|
||||
case "Normal":
|
||||
@@ -298,11 +321,17 @@ namespace Terminal.Gui {
|
||||
/// The default ColorSchemes for the application.
|
||||
/// </summary>
|
||||
public static class Colors {
|
||||
private static ColorScheme _toplevel;
|
||||
private static ColorScheme _base;
|
||||
private static ColorScheme _dialog;
|
||||
private static ColorScheme _menu;
|
||||
private static ColorScheme _error;
|
||||
|
||||
/// <summary>
|
||||
/// The application toplevel color scheme, for the default toplevel views.
|
||||
/// </summary>
|
||||
public static ColorScheme TopLevel { get { return _toplevel; } set { _toplevel = SetColorScheme (value); } }
|
||||
|
||||
/// <summary>
|
||||
/// The base color scheme, for the default toplevel views.
|
||||
/// </summary>
|
||||
@@ -325,7 +354,7 @@ namespace Terminal.Gui {
|
||||
|
||||
private static ColorScheme SetColorScheme (ColorScheme colorScheme, [CallerMemberName]string callerMemberName = null)
|
||||
{
|
||||
colorScheme.Caller = callerMemberName;
|
||||
colorScheme.caller = callerMemberName;
|
||||
return colorScheme;
|
||||
}
|
||||
}
|
||||
@@ -400,6 +429,9 @@ namespace Terminal.Gui {
|
||||
/// ConsoleDriver is an abstract class that defines the requirements for a console driver. One implementation if the CursesDriver, and another one uses the .NET Console one.
|
||||
/// </summary>
|
||||
public abstract class ConsoleDriver {
|
||||
/// <summary>
|
||||
/// The handler fired when the terminal is resized.
|
||||
/// </summary>
|
||||
protected Action TerminalResized;
|
||||
|
||||
/// <summary>
|
||||
@@ -431,6 +463,12 @@ namespace Terminal.Gui {
|
||||
/// </summary>
|
||||
/// <param name="str">String.</param>
|
||||
public abstract void AddStr (ustring str);
|
||||
/// <summary>
|
||||
/// Prepare the driver and set the key and mouse events handlers.
|
||||
/// </summary>
|
||||
/// <param name="mainLoop"></param>
|
||||
/// <param name="keyHandler"></param>
|
||||
/// <param name="mouseHandler"></param>
|
||||
public abstract void PrepareToRun (MainLoop mainLoop, Action<KeyEvent> keyHandler, Action<MouseEvent> mouseHandler);
|
||||
|
||||
/// <summary>
|
||||
@@ -459,7 +497,11 @@ namespace Terminal.Gui {
|
||||
/// <param name="c">C.</param>
|
||||
public abstract void SetAttribute (Attribute c);
|
||||
|
||||
// Set Colors from limit sets of colors
|
||||
/// <summary>
|
||||
/// Set Colors from limit sets of colors.
|
||||
/// </summary>
|
||||
/// <param name="foreground">Foreground.</param>
|
||||
/// <param name="background">Background.</param>
|
||||
public abstract void SetColors (ConsoleColor foreground, ConsoleColor background);
|
||||
|
||||
// Advanced uses - set colors to any pre-set pairs, you would need to init_color
|
||||
@@ -472,6 +514,10 @@ namespace Terminal.Gui {
|
||||
/// <param name="backgroundColorId">Background color identifier.</param>
|
||||
public abstract void SetColors (short foregroundColorId, short backgroundColorId);
|
||||
|
||||
/// <summary>
|
||||
/// Set the handler when the terminal is resized.
|
||||
/// </summary>
|
||||
/// <param name="terminalResized"></param>
|
||||
public void SetTerminalResized(Action terminalResized)
|
||||
{
|
||||
TerminalResized = terminalResized;
|
||||
@@ -555,7 +601,14 @@ namespace Terminal.Gui {
|
||||
set => this.clip = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start of mouse moves.
|
||||
/// </summary>
|
||||
public abstract void StartReportingMouseMoves ();
|
||||
|
||||
/// <summary>
|
||||
/// Stop reporting mouses moves.
|
||||
/// </summary>
|
||||
public abstract void StopReportingMouseMoves ();
|
||||
|
||||
/// <summary>
|
||||
@@ -628,6 +681,12 @@ namespace Terminal.Gui {
|
||||
/// </summary>
|
||||
public Rune BottomTee;
|
||||
|
||||
/// <summary>
|
||||
/// Make the attribute for the foreground and background colors.
|
||||
/// </summary>
|
||||
/// <param name="fore">Foreground.</param>
|
||||
/// <param name="back">Background.</param>
|
||||
/// <returns></returns>
|
||||
public abstract Attribute MakeAttribute (Color fore, Color back);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -437,10 +437,17 @@ namespace Terminal.Gui {
|
||||
|
||||
public WindowsDriver ()
|
||||
{
|
||||
Colors.TopLevel = new ColorScheme ();
|
||||
|
||||
Colors.TopLevel.Normal = MakeColor (ConsoleColor.Green, ConsoleColor.Black);
|
||||
Colors.TopLevel.Focus = MakeColor (ConsoleColor.White, ConsoleColor.DarkCyan);
|
||||
Colors.TopLevel.HotNormal = MakeColor (ConsoleColor.DarkYellow, ConsoleColor.Black);
|
||||
Colors.TopLevel.HotFocus = MakeColor (ConsoleColor.DarkYellow, ConsoleColor.DarkCyan);
|
||||
|
||||
winConsole = new WindowsConsole ();
|
||||
|
||||
cols = Console.WindowWidth;
|
||||
rows = Console.WindowHeight - 1;
|
||||
rows = Console.WindowHeight;
|
||||
WindowsConsole.SmallRect.MakeEmpty (ref damageRegion);
|
||||
|
||||
ResizeScreen ();
|
||||
@@ -520,7 +527,6 @@ namespace Terminal.Gui {
|
||||
} finally {
|
||||
eventReady.Reset();
|
||||
}
|
||||
//Debug.WriteLine("Events ready");
|
||||
|
||||
if (!tokenSource.IsCancellationRequested)
|
||||
return result != null;
|
||||
@@ -574,16 +580,17 @@ namespace Terminal.Gui {
|
||||
private WindowsConsole.ButtonState? LastMouseButtonPressed = null;
|
||||
private bool IsButtonReleased = false;
|
||||
private bool IsButtonDoubleClicked = false;
|
||||
private object token;
|
||||
|
||||
private MouseEvent ToDriverMouse (WindowsConsole.MouseEventRecord mouseEvent)
|
||||
{
|
||||
MouseFlags mouseFlag = MouseFlags.AllEvents;
|
||||
|
||||
if (token != null)
|
||||
Application.MainLoop.RemoveTimeout (token);
|
||||
if (IsButtonDoubleClicked)
|
||||
token = Application.MainLoop.AddTimeout (TimeSpan.FromMilliseconds (300), timer);
|
||||
if (IsButtonDoubleClicked) {
|
||||
Task.Run (async () => {
|
||||
await Task.Delay (300);
|
||||
_ = new Action (() => IsButtonDoubleClicked = false);
|
||||
});
|
||||
}
|
||||
|
||||
// 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
|
||||
@@ -595,7 +602,6 @@ namespace Terminal.Gui {
|
||||
IsButtonReleased = false;
|
||||
}
|
||||
|
||||
//Debug.WriteLine ($"MouseEventRecord: {mouseEvent}");
|
||||
if ((mouseEvent.EventFlags == 0 && LastMouseButtonPressed == null && !IsButtonDoubleClicked) ||
|
||||
(mouseEvent.EventFlags == WindowsConsole.EventFlags.MouseMoved &&
|
||||
mouseEvent.ButtonState != 0 && !IsButtonDoubleClicked)) {
|
||||
@@ -696,7 +702,6 @@ namespace Terminal.Gui {
|
||||
|
||||
mouseFlag = SetControlKeyStates (mouseEvent, mouseFlag);
|
||||
|
||||
Debug.WriteLine ($"MouseFlags: {mouseFlag}");
|
||||
return new MouseEvent () {
|
||||
X = mouseEvent.MousePosition.X,
|
||||
Y = mouseEvent.MousePosition.Y,
|
||||
@@ -719,12 +724,6 @@ namespace Terminal.Gui {
|
||||
return mouseFlag;
|
||||
}
|
||||
|
||||
bool timer (MainLoop caller)
|
||||
{
|
||||
IsButtonDoubleClicked = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
public ConsoleKeyInfoEx ToConsoleKeyInfoEx (WindowsConsole.KeyEventRecord keyEvent)
|
||||
{
|
||||
var state = keyEvent.dwControlKeyState;
|
||||
@@ -818,9 +817,12 @@ namespace Terminal.Gui {
|
||||
return (Key)((uint)Key.ControlA + delta);
|
||||
if (keyInfo.Modifiers == ConsoleModifiers.Alt)
|
||||
return (Key)(((uint)Key.AltMask) | ((uint)'A' + delta));
|
||||
// TODO: Only apply after pull requests at NStack are merged.
|
||||
//if ((keyInfo.Modifiers & (ConsoleModifiers.Alt | ConsoleModifiers.Control)) != 0)
|
||||
// return (Key)((uint)keyInfo.KeyChar);
|
||||
if ((keyInfo.Modifiers & (ConsoleModifiers.Alt | ConsoleModifiers.Control)) != 0) {
|
||||
if (keyInfo.KeyChar == 0)
|
||||
return (Key)(((uint)Key.AltMask) + ((uint)Key.ControlA + delta));
|
||||
else
|
||||
return (Key)((uint)keyInfo.KeyChar);
|
||||
}
|
||||
return (Key)((uint)alphaBase + delta);
|
||||
}
|
||||
if (key >= ConsoleKey.D0 && key <= ConsoleKey.D9) {
|
||||
@@ -900,7 +902,7 @@ namespace Terminal.Gui {
|
||||
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].Attributes = (ushort)Colors.TopLevel.Normal;
|
||||
OutputBuffer [position].Char.UnicodeChar = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -448,6 +448,21 @@ namespace Terminal.Gui {
|
||||
/// </summary>
|
||||
public MouseFlags Flags;
|
||||
|
||||
/// <summary>
|
||||
/// The offset X (column) location for the mouse event.
|
||||
/// </summary>
|
||||
public int OfX;
|
||||
|
||||
/// <summary>
|
||||
/// The offset Y (column) location for the mouse event.
|
||||
/// </summary>
|
||||
public int OfY;
|
||||
|
||||
/// <summary>
|
||||
/// The current view at the location for the mouse event.
|
||||
/// </summary>
|
||||
public View View;
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:Terminal.Gui.MouseEvent"/>.
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user