mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
Improve label
This commit is contained in:
54
Core.cs
54
Core.cs
@@ -7,6 +7,7 @@
|
|||||||
// Optimziations
|
// Optimziations
|
||||||
// - Add rendering limitation to the exposed area
|
// - Add rendering limitation to the exposed area
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Terminal {
|
namespace Terminal {
|
||||||
@@ -22,7 +23,7 @@ namespace Terminal {
|
|||||||
public virtual void MouseEvent (Event.Mouse me) { }
|
public virtual void MouseEvent (Event.Mouse me) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class View : Responder {
|
public class View : Responder, IEnumerable {
|
||||||
View container = null;
|
View container = null;
|
||||||
View focused = null;
|
View focused = null;
|
||||||
public static ConsoleDriver Driver = Application.Driver;
|
public static ConsoleDriver Driver = Application.Driver;
|
||||||
@@ -34,9 +35,6 @@ namespace Terminal {
|
|||||||
// The frame for the object
|
// The frame for the object
|
||||||
Rect frame;
|
Rect frame;
|
||||||
|
|
||||||
// The offset of the first child view inside the view
|
|
||||||
Point offset;
|
|
||||||
|
|
||||||
// The frame for this view
|
// The frame for this view
|
||||||
public Rect Frame {
|
public Rect Frame {
|
||||||
get => frame;
|
get => frame;
|
||||||
@@ -46,6 +44,12 @@ namespace Terminal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IEnumerator GetEnumerator ()
|
||||||
|
{
|
||||||
|
foreach (var v in subviews)
|
||||||
|
yield return v;
|
||||||
|
}
|
||||||
|
|
||||||
public Rect Bounds {
|
public Rect Bounds {
|
||||||
get => new Rect (Point.Empty, Frame.Size);
|
get => new Rect (Point.Empty, Frame.Size);
|
||||||
set {
|
set {
|
||||||
@@ -75,7 +79,7 @@ namespace Terminal {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public void Add (View view)
|
public virtual void Add (View view)
|
||||||
{
|
{
|
||||||
if (view == null)
|
if (view == null)
|
||||||
return;
|
return;
|
||||||
@@ -150,8 +154,8 @@ namespace Terminal {
|
|||||||
internal void ViewToScreen (int col, int row, out int rcol, out int rrow, bool clipped = true)
|
internal void ViewToScreen (int col, int row, out int rcol, out int rrow, bool clipped = true)
|
||||||
{
|
{
|
||||||
// Computes the real row, col relative to the screen.
|
// Computes the real row, col relative to the screen.
|
||||||
rrow = row + frame.X;
|
rrow = row + frame.Y;
|
||||||
rcol = col + frame.Y;
|
rcol = col + frame.X;
|
||||||
var ccontainer = container;
|
var ccontainer = container;
|
||||||
while (ccontainer != null) {
|
while (ccontainer != null) {
|
||||||
rrow += ccontainer.frame.Y;
|
rrow += ccontainer.frame.Y;
|
||||||
@@ -238,15 +242,17 @@ namespace Terminal {
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performs a redraw of this view and its subviews, only redraws the views that have been flagged for a re-display.
|
/// Performs a redraw of this view and its subviews, only redraws the views that have been flagged for a re-display.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual void Redraw ()
|
public virtual void Redraw (Rect region)
|
||||||
{
|
{
|
||||||
var clipRect = new Rect (offset, frame.Size);
|
var clipRect = new Rect (Point.Empty, frame.Size);
|
||||||
|
|
||||||
if (subviews != null) {
|
if (subviews != null) {
|
||||||
foreach (var view in subviews) {
|
foreach (var view in subviews) {
|
||||||
if (view.NeedDisplay) {
|
if (view.NeedDisplay) {
|
||||||
if (view.Frame.IntersectsWith (clipRect)) {
|
if (view.Frame.IntersectsWith (clipRect) && view.Frame.IntersectsWith (region)) {
|
||||||
view.Redraw ();
|
|
||||||
|
// TODO: optimize this by computing the intersection of region and view.Bounds
|
||||||
|
view.Redraw (view.Bounds);
|
||||||
}
|
}
|
||||||
view.NeedDisplay = false;
|
view.NeedDisplay = false;
|
||||||
}
|
}
|
||||||
@@ -434,7 +440,7 @@ namespace Terminal {
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A toplevel view that draws a frame around its region
|
/// A toplevel view that draws a frame around its region
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Window : Toplevel {
|
public class Window : Toplevel, IEnumerable {
|
||||||
View contentView;
|
View contentView;
|
||||||
string title;
|
string title;
|
||||||
|
|
||||||
@@ -451,7 +457,12 @@ namespace Terminal {
|
|||||||
this.Title = title;
|
this.Title = title;
|
||||||
frame.Inflate (-1, -1);
|
frame.Inflate (-1, -1);
|
||||||
contentView = new View (frame);
|
contentView = new View (frame);
|
||||||
Add(contentView);
|
base.Add(contentView);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator GetEnumerator ()
|
||||||
|
{
|
||||||
|
return contentView.GetEnumerator ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrawFrame ()
|
void DrawFrame ()
|
||||||
@@ -459,7 +470,12 @@ namespace Terminal {
|
|||||||
DrawFrame (new Rect(0, 0, Frame.Width, Frame.Height), true);
|
DrawFrame (new Rect(0, 0, Frame.Width, Frame.Height), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Redraw ()
|
public override void Add (View view)
|
||||||
|
{
|
||||||
|
contentView.Add (view);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Redraw (Rect bounds)
|
||||||
{
|
{
|
||||||
Driver.SetColor (Colors.Base.Normal);
|
Driver.SetColor (Colors.Base.Normal);
|
||||||
DrawFrame ();
|
DrawFrame ();
|
||||||
@@ -474,7 +490,7 @@ namespace Terminal {
|
|||||||
Driver.AddCh (' ');
|
Driver.AddCh (' ');
|
||||||
}
|
}
|
||||||
Driver.SetColor (Colors.Dialog.Normal);
|
Driver.SetColor (Colors.Dialog.Normal);
|
||||||
contentView.Redraw ();
|
contentView.Redraw (contentView.Bounds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -579,13 +595,13 @@ namespace Terminal {
|
|||||||
|
|
||||||
static void Redraw (View view)
|
static void Redraw (View view)
|
||||||
{
|
{
|
||||||
view.Redraw ();
|
view.Redraw (view.Bounds);
|
||||||
Driver.Refresh ();
|
Driver.Refresh ();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Refresh (View view)
|
static void Refresh (View view)
|
||||||
{
|
{
|
||||||
view.Redraw ();
|
view.Redraw (view.Bounds);
|
||||||
Driver.Refresh ();
|
Driver.Refresh ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -594,7 +610,7 @@ namespace Terminal {
|
|||||||
Driver.RedrawTop ();
|
Driver.RedrawTop ();
|
||||||
View last = null;
|
View last = null;
|
||||||
foreach (var v in toplevels){
|
foreach (var v in toplevels){
|
||||||
v.Redraw ();
|
v.Redraw (v.Bounds);
|
||||||
last = v;
|
last = v;
|
||||||
}
|
}
|
||||||
if (last != null)
|
if (last != null)
|
||||||
@@ -635,7 +651,7 @@ namespace Terminal {
|
|||||||
} else if (wait == false)
|
} else if (wait == false)
|
||||||
return;
|
return;
|
||||||
if (state.Toplevel.NeedDisplay)
|
if (state.Toplevel.NeedDisplay)
|
||||||
state.Toplevel.Redraw ();
|
state.Toplevel.Redraw (state.Toplevel.Bounds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ namespace Terminal {
|
|||||||
|
|
||||||
public static class Colors {
|
public static class Colors {
|
||||||
public static ColorScheme Base, Dialog, Menu, Error;
|
public static ColorScheme Base, Dialog, Menu, Error;
|
||||||
|
|
||||||
|
public
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class ConsoleDriver {
|
public abstract class ConsoleDriver {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Terminal {
|
namespace Terminal {
|
||||||
public enum TextAlignment {
|
public enum TextAlignment {
|
||||||
@@ -10,6 +12,8 @@ namespace Terminal {
|
|||||||
/// Label widget, displays a string at a given position, can include multiple lines.
|
/// Label widget, displays a string at a given position, can include multiple lines.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Label : View {
|
public class Label : View {
|
||||||
|
List<string> lines = new List<string> ();
|
||||||
|
bool recalcPending = true;
|
||||||
string text;
|
string text;
|
||||||
TextAlignment textAlignment;
|
TextAlignment textAlignment;
|
||||||
|
|
||||||
@@ -51,8 +55,64 @@ namespace Terminal {
|
|||||||
this.text = text;
|
this.text = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Redraw ()
|
static char [] whitespace = new char [] { ' ', '\t' };
|
||||||
|
|
||||||
|
string ClipAndJustify (string str)
|
||||||
{
|
{
|
||||||
|
int slen = str.Length;
|
||||||
|
if (slen > Frame.Width)
|
||||||
|
return str.Substring (0, Frame.Width);
|
||||||
|
else {
|
||||||
|
if (textAlignment == TextAlignment.Justified) {
|
||||||
|
var words = str.Split (whitespace, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
int textCount = words.Sum ((arg) => arg.Length);
|
||||||
|
|
||||||
|
var spaces = (Frame.Width - textCount) / (words.Length - 1);
|
||||||
|
var extras = (Frame.Width - textCount) % words.Length;
|
||||||
|
var s = new System.Text.StringBuilder ();
|
||||||
|
//s.Append ($"tc={textCount} sp={spaces},x={extras} - ");
|
||||||
|
for (int w = 0; w < words.Length; w++) {
|
||||||
|
var x = words [w];
|
||||||
|
s.Append (x);
|
||||||
|
if (w + 1 < words.Length)
|
||||||
|
for (int i = 0; i < spaces; i++)
|
||||||
|
s.Append (' ');
|
||||||
|
if (extras > 0) {
|
||||||
|
s.Append ('_');
|
||||||
|
extras--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s.ToString ();
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Recalc ()
|
||||||
|
{
|
||||||
|
lines.Clear ();
|
||||||
|
if (text.IndexOf ('\n') == -1) {
|
||||||
|
lines.Add (ClipAndJustify (text));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int textLen = text.Length;
|
||||||
|
int lp = 0;
|
||||||
|
for (int i = 0; i < textLen; i++) {
|
||||||
|
char c = text [i];
|
||||||
|
|
||||||
|
if (c == '\n') {
|
||||||
|
lines.Add (ClipAndJustify (text.Substring (lp, i - lp)));
|
||||||
|
lp = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
recalcPending = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Redraw (Rect region)
|
||||||
|
{
|
||||||
|
if (recalcPending)
|
||||||
|
Recalc ();
|
||||||
|
|
||||||
if (TextColor != -1)
|
if (TextColor != -1)
|
||||||
Driver.SetColor (TextColor);
|
Driver.SetColor (TextColor);
|
||||||
else
|
else
|
||||||
@@ -60,7 +120,28 @@ namespace Terminal {
|
|||||||
|
|
||||||
Clear ();
|
Clear ();
|
||||||
Move (Frame.X, Frame.Y);
|
Move (Frame.X, Frame.Y);
|
||||||
Driver.AddStr (text);
|
for (int line = 0; line < lines.Count; line++) {
|
||||||
|
if (line < region.Top || line >= region.Bottom)
|
||||||
|
continue;
|
||||||
|
var str = lines [line];
|
||||||
|
int x;
|
||||||
|
switch (textAlignment) {
|
||||||
|
case TextAlignment.Left:
|
||||||
|
case TextAlignment.Justified:
|
||||||
|
x = 0;
|
||||||
|
break;
|
||||||
|
case TextAlignment.Right:
|
||||||
|
x = Frame.Right - str.Length;
|
||||||
|
break;
|
||||||
|
case TextAlignment.Centered:
|
||||||
|
x = Frame.Left + (Frame.Width - str.Length) / 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException ();
|
||||||
|
}
|
||||||
|
Move (x, line);
|
||||||
|
Driver.AddStr (str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -70,6 +151,7 @@ namespace Terminal {
|
|||||||
get => text;
|
get => text;
|
||||||
set {
|
set {
|
||||||
text = value;
|
text = value;
|
||||||
|
recalcPending = true;
|
||||||
SetNeedsDisplay ();
|
SetNeedsDisplay ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
8
demo.cs
8
demo.cs
@@ -5,7 +5,13 @@ class Demo {
|
|||||||
{
|
{
|
||||||
Application.Init ();
|
Application.Init ();
|
||||||
var top = Application.Top;
|
var top = Application.Top;
|
||||||
top.Add (new Window (new Rect (0, 0, 80, 24), "Hello"));
|
var win = new Window (new Rect (0, 0, 80, 24), "Hello") {
|
||||||
|
new Label (new Rect (0, 0, 40, 3), "1-Hello world, how are you doing today") { TextAlignment = TextAlignment.Left },
|
||||||
|
new Label (new Rect (0, 4, 40, 3), "2-Hello world, how are you doing today") { TextAlignment = TextAlignment.Right},
|
||||||
|
new Label (new Rect (0, 8, 40, 3), "3-Hello world, how are you doing today") { TextAlignment = TextAlignment.Centered },
|
||||||
|
new Label (new Rect (0, 12, 40, 3), "4-Hello world, how are you doing today") { TextAlignment = TextAlignment.Justified}
|
||||||
|
};
|
||||||
|
top.Add (win);
|
||||||
Application.Run ();
|
Application.Run ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user