Browse Source

Fixes #134. TextView: Add line wrapping. (#1147)

* Fixes #134. TextView: Add line wrapping.

* Facilitates exception handling in Debug mode.

* Fixes the cursor position if it is always on the same line.

* Fixed TextView column position and hiding the cursor if it is outside outbound frame.

* Added more wrap lines features.. Added a BottomOffset property. Fixed Ctrl+K and Ctrl+Y.

* Fixes the Text property and fixing a redraw behavior not cleaning well at right.

* Fixes Ctrl+K from adding an extra line feed.

* Implemented Ctrl+K and Ctrl-Y on wrapped lines and preventing left Column to be greater than 0 on wrap.

* Fixes more line feed issues.

* More line feed fixing.

* Fixes UpdateModel that must return the new row and new column from the wrapped lines.

* Fixes #1155. MoveForward/MoveBackward not bound on Text controls.

* Added much more features to TextView.

* Fixes ResetPosition and forcing the cursor visibility.

* Implemented the New, Save and SaveAs methods in the Editor.
BDisp 4 years ago
parent
commit
0669e2cc94

+ 8 - 2
Terminal.Gui/Core/Application.cs

@@ -702,8 +702,13 @@ namespace Terminal.Gui {
 			var resume = true;
 			while (resume)
 			{
-				try
-				{
+#if DEBUG
+				resume = false;
+				var runToken = Begin (view);
+				RunLoop (runToken);
+				End (runToken);
+#else
+				try {
 					resume = false;
 					var runToken = Begin (view);
 					RunLoop (runToken);
@@ -717,6 +722,7 @@ namespace Terminal.Gui {
 					}
 					resume = errorHandler(error);
 				}
+#endif
 			}
 		}
 

+ 4 - 0
Terminal.Gui/Core/View.cs

@@ -1471,6 +1471,8 @@ namespace Terminal.Gui {
 			KeyPress?.Invoke (args);
 			if (args.Handled)
 				return true;
+			if (Focused?.ProcessKey (keyEvent) == true)
+				return true;
 			if (subviews == null || subviews.Count == 0)
 				return false;
 			foreach (var view in subviews)
@@ -1486,6 +1488,8 @@ namespace Terminal.Gui {
 			KeyPress?.Invoke (args);
 			if (args.Handled)
 				return true;
+			if (Focused?.ProcessKey (keyEvent) == true)
+				return true;
 			if (subviews == null || subviews.Count == 0)
 				return false;
 			foreach (var view in subviews)

+ 5 - 3
Terminal.Gui/Views/TextField.cs

@@ -389,6 +389,7 @@ namespace Terminal.Gui {
 
 			case Key.CursorLeft | Key.ShiftMask | Key.CtrlMask:
 			case Key.CursorUp | Key.ShiftMask | Key.CtrlMask:
+			case (Key)((int)'B' + Key.ShiftMask | Key.AltMask):
 				if (point > 0) {
 					int x = start > -1 && start > point ? start : point;
 					if (x > 0) {
@@ -402,6 +403,7 @@ namespace Terminal.Gui {
 
 			case Key.CursorRight | Key.ShiftMask | Key.CtrlMask:
 			case Key.CursorDown | Key.ShiftMask | Key.CtrlMask:
+			case (Key)((int)'F' + Key.ShiftMask | Key.AltMask):
 				if (point < text.Count) {
 					int x = start > -1 && start > point ? start : point;
 					int sfw = WordForward (x);
@@ -503,7 +505,7 @@ namespace Terminal.Gui {
 
 			case Key.CursorLeft | Key.CtrlMask:
 			case Key.CursorUp | Key.CtrlMask:
-			case (Key)((int)'b' + Key.AltMask):
+			case (Key)((int)'B' + Key.AltMask):
 				ClearAllSelection ();
 				int bw = WordBackward (point);
 				if (bw != -1)
@@ -513,7 +515,7 @@ namespace Terminal.Gui {
 
 			case Key.CursorRight | Key.CtrlMask:
 			case Key.CursorDown | Key.CtrlMask:
-			case (Key)((int)'f' + Key.AltMask):
+			case (Key)((int)'F' + Key.AltMask):
 				ClearAllSelection ();
 				int fw = WordForward (point);
 				if (fw != -1)
@@ -604,7 +606,7 @@ namespace Terminal.Gui {
 				}
 			}
 			if (i != p)
-				return i;
+				return i + 1;
 			return -1;
 		}
 

File diff suppressed because it is too large
+ 576 - 73
Terminal.Gui/Views/TextView.cs


+ 117 - 23
UICatalog/Scenarios/Editor.cs

@@ -14,6 +14,7 @@ namespace UICatalog {
 		private TextView _textView;
 		private bool _saved = true;
 		private ScrollBarView _scrollBar;
+		private byte [] _originalText;
 
 		public override void Init (Toplevel top, ColorScheme colorScheme)
 		{
@@ -28,13 +29,14 @@ namespace UICatalog {
 					new MenuItem ("_New", "", () => New()),
 					new MenuItem ("_Open", "", () => Open()),
 					new MenuItem ("_Save", "", () => Save()),
+					new MenuItem ("_Save As", "", () => SaveAs()),
 					null,
 					new MenuItem ("_Quit", "", () => Quit()),
 				}),
 				new MenuBarItem ("_Edit", new MenuItem [] {
-					new MenuItem ("_Copy", "", () => Copy()),
-					new MenuItem ("C_ut", "", () => Cut()),
-					new MenuItem ("_Paste", "", () => Paste())
+					new MenuItem ("_Copy", "", () => Copy(),null,null, Key.CtrlMask | Key.C),
+					new MenuItem ("C_ut", "", () => Cut(),null,null, Key.CtrlMask | Key.W),
+					new MenuItem ("_Paste", "", () => Paste(),null,null, Key.CtrlMask | Key.Y)
 				}),
 				new MenuBarItem ("_ScrollBarView", CreateKeepChecked ()),
 				new MenuBarItem ("_Cursor", new MenuItem [] {
@@ -49,7 +51,8 @@ namespace UICatalog {
 					new MenuItem ("  V_ertical Fix", "", () => SetCursor(CursorVisibility.VerticalFix)),
 					new MenuItem ("  B_ox Fix", "", () => SetCursor(CursorVisibility.BoxFix)),
 					new MenuItem ("  U_nderline Fix","", () => SetCursor(CursorVisibility.UnderlineFix))
-				})
+				}),
+				new MenuBarItem ("Forma_t", CreateWrapChecked ())
 			});
 			Top.Add (menu);
 
@@ -76,7 +79,8 @@ namespace UICatalog {
 				Y = 0,
 				Width = Dim.Fill (),
 				Height = Dim.Fill (),
-
+				BottomOffset = 1,
+				RightOffset = 1
 			};
 
 			LoadFile ();
@@ -102,10 +106,12 @@ namespace UICatalog {
 			};
 
 			_textView.DrawContent += (e) => {
-				_scrollBar.Size = _textView.Lines - 1;
+				_scrollBar.Size = _textView.Lines;
 				_scrollBar.Position = _textView.TopRow;
-				_scrollBar.OtherScrollBarView.Size = _textView.Maxlength;
-				_scrollBar.OtherScrollBarView.Position = _textView.LeftColumn;
+				if (_scrollBar.OtherScrollBarView != null) {
+					_scrollBar.OtherScrollBarView.Size = _textView.Maxlength;
+					_scrollBar.OtherScrollBarView.Position = _textView.LeftColumn;
+				}
 				_scrollBar.LayoutSubviews ();
 				_scrollBar.Refresh ();
 			};
@@ -117,20 +123,23 @@ namespace UICatalog {
 
 		private void New ()
 		{
-			Win.Title = _fileName = "Untitled";
-			throw new NotImplementedException ();
+			if (!CanCloseFile ()) {
+				return;
+			}
+
+			Win.Title = "Untitled.txt";
+			_fileName = null;
+			_originalText = new System.IO.MemoryStream ().ToArray ();
+			_textView.Text = _originalText;
 		}
 
 		private void LoadFile ()
 		{
-			if (!_saved) {
-				MessageBox.ErrorQuery ("Not Implemented", "Functionality not yet implemented.", "Ok");
-			}
-
 			if (_fileName != null) {
 				// BUGBUG: #452 TextView.LoadFile keeps file open and provides no way of closing it
 				//_textView.LoadFile(_fileName);
 				_textView.Text = System.IO.File.ReadAllText (_fileName);
+				_originalText = _textView.Text.ToByteArray ();
 				Win.Title = _fileName;
 				_saved = true;
 			}
@@ -138,20 +147,23 @@ namespace UICatalog {
 
 		private void Paste ()
 		{
-			MessageBox.ErrorQuery ("Not Implemented", "Functionality not yet implemented.", "Ok");
+			if (_textView != null) {
+				_textView.Paste ();
+			}
 		}
 
 		private void Cut ()
 		{
-			MessageBox.ErrorQuery ("Not Implemented", "Functionality not yet implemented.", "Ok");
+			if (_textView != null) {
+				_textView.Cut ();
+			}
 		}
 
 		private void Copy ()
 		{
-			MessageBox.ErrorQuery ("Not Implemented", "Functionality not yet implemented.", "Ok");
-			//if (_textView != null && _textView.SelectedLength != 0) {
-			//	_textView.Copy ();
-			//}
+			if (_textView != null) {
+				_textView.Copy ();
+			}
 		}
 
 		private void SetCursor (CursorVisibility visibility)
@@ -159,8 +171,29 @@ namespace UICatalog {
 			_textView.DesiredCursorVisibility = visibility;
 		}
 
+		private bool CanCloseFile ()
+		{
+			if (_textView.Text == _originalText) {
+				return true;
+			}
+
+			var r = MessageBox.ErrorQuery ("Save File",
+				$"Do you want save changes in {Win.Title}?", "Yes", "No", "Cancel");
+			if (r == 0) {
+				return Save ();
+			} else if (r == 1) {
+				return true;
+			}
+
+			return false;
+		}
+
 		private void Open ()
 		{
+			if (!CanCloseFile ()) {
+				return;
+			}
+
 			var d = new OpenDialog ("Open", "Open a file") { AllowsMultipleSelection = false };
 			Application.Run (d);
 
@@ -170,14 +203,54 @@ namespace UICatalog {
 			}
 		}
 
-		private void Save ()
+		private bool Save ()
 		{
 			if (_fileName != null) {
 				// BUGBUG: #279 TextView does not know how to deal with \r\n, only \r 
 				// As a result files saved on Windows and then read back will show invalid chars.
-				System.IO.File.WriteAllText (_fileName, _textView.Text.ToString());
+				return SaveFile (Win.Title.ToString (), _fileName);
+			} else {
+				return SaveAs ();
+			}
+		}
+
+		private bool SaveAs ()
+		{
+			var sd = new SaveDialog ("Save file", "Choose the path where to save the file.");
+			sd.FilePath = System.IO.Path.Combine (sd.FilePath.ToString (), Win.Title.ToString ());
+			Application.Run (sd);
+
+			if (!sd.Canceled) {
+				if (System.IO.File.Exists (sd.FilePath.ToString ())) {
+					if (MessageBox.Query ("Save File",
+						"File already exists. Overwrite any way?", "No", "Ok") == 1) {
+						return SaveFile (sd.FileName.ToString (), sd.FilePath.ToString ());
+					} else {
+						return _saved = false;
+					}
+				} else {
+					return SaveFile (sd.FileName.ToString (), sd.FilePath.ToString ());
+				}
+			} else {
+				return _saved = false;
+			}
+		}
+
+		private bool SaveFile (string title, string file)
+		{
+			try {
+				Win.Title = title;
+				_fileName = file;
+				System.IO.File.WriteAllText (_fileName, _textView.Text.ToString ());
 				_saved = true;
+				MessageBox.Query ("Save File", "File was successfully saved.", "Ok");
+
+			} catch (Exception ex) {
+				MessageBox.ErrorQuery ("Error", ex.Message, "Ok");
+				return false;
 			}
+
+			return true;
 		}
 
 		private void Quit ()
@@ -185,7 +258,7 @@ namespace UICatalog {
 			Application.RequestStop ();
 		}
 
-		private void CreateDemoFile(string fileName)
+		private void CreateDemoFile (string fileName)
 		{
 			var sb = new StringBuilder ();
 			// BUGBUG: #279 TextView does not know how to deal with \r\n, only \r
@@ -211,6 +284,27 @@ namespace UICatalog {
 			return new MenuItem [] { item };
 		}
 
+		private MenuItem [] CreateWrapChecked ()
+		{
+			var item = new MenuItem ();
+			item.Title = "Word Wrap";
+			item.CheckType |= MenuItemCheckStyle.Checked;
+			item.Checked = false;
+			item.Action += () => {
+				_textView.WordWrap = item.Checked = !item.Checked;
+				if (_textView.WordWrap) {
+					_scrollBar.AutoHideScrollBars = false;
+					_scrollBar.OtherScrollBarView.ShowScrollIndicator = false;
+					_textView.BottomOffset = 0;
+				} else {
+					_scrollBar.AutoHideScrollBars = true;
+					_textView.BottomOffset = 1;
+				}
+			};
+
+			return new MenuItem [] { item };
+		}
+
 		public override void Run ()
 		{
 			base.Run ();

Some files were not shown because too many files changed in this diff