forked from SamuelKinnett/simple-console-gui
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ConsoleGUI.cs
295 lines (249 loc) · 10.9 KB
/
ConsoleGUI.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace simple_console_gui
{
/// <summary>
/// This class provides methods to create and manage GUI-like elements in a console environment.
/// </summary>
public class ConsoleGUI
{
#region ConsoleGUI base class
ConsoleRenderer consoleRenderer;
List<Element> screen;
int numberOfElements;
int activeElement;
ConsoleColor screenColour { get; set; }
/// <summary>
/// Instantiates a new console GUI, creating a consoleRenderer and an array to hold the GUI elements.
/// </summary>
public ConsoleGUI(ConsoleColor screenColour = ConsoleColor.Black)
{
consoleRenderer = new ConsoleRenderer(Console.WindowWidth, Console.WindowHeight);
screen = new List<Element>(); //This list contains every element to be drawn to the screen. Elements are rendered in the order they're added to the list.
numberOfElements = -1;
activeElement = -1;
this.screenColour = screenColour;
Console.BackgroundColor = screenColour;
Console.Clear ();
}
/// <summary>
/// Draws all the elements to the screen.
/// </summary>
public void PaintScreen()
{
foreach (Element currentElement in screen) {
currentElement.DrawElement(consoleRenderer);
}
consoleRenderer.Paint(screenColour);
}
public string Interact()
{
return screen[activeElement].Interact();
}
public void Update()
{
foreach (Element currentElement in screen) {
currentElement.Update();
}
}
/// <summary>
/// Adds an element to the screen
/// </summary>
public void AddElement(Element newElement, bool makeActive = false)
{
screen.Add(newElement);
numberOfElements++;
if (makeActive) {
activeElement = numberOfElements++;
}
}
#endregion
#region Element
/// <summary>
/// This class provides the basic features of a GUI element that can then be inherited from.
/// </summary>
public abstract class Element
{
public int xPosition; //The x position of the element
public int yPosition; //The y position of the element
public int width; //The width of the element in characters
public int height; //The height of the element in characters
public ConsoleColor foreColour; //The foreground colour of the element
public ConsoleColor backColour; //The background colour of the element
public BorderStyles border; //The style of border of the element. Borders are always internal.
public abstract void DrawElement(ConsoleRenderer consoleRenderer); //Called to draw the element to the buffer.
public abstract void DeleteElement(); //Called to remove the element when it is no longer needed.
public abstract void Update(); //Called to update the element.
public abstract string Interact(); //Called to interact with the element.
internal Element()
{
//Used to stop the abstract class being instantiated
}
}
#endregion
#region Log Box
/// <summary>
/// This class fulfils the same basic purpose as the standard console; it stores lines in a buffer that can then be rendered.
/// </summary>
public class LogBox : Element
{
int bufferSize; //The size of the text buffer
string[] buffer; //The contents of the log box.
public LogBox(int x, int y, int width, int height, BorderStyles border = BorderStyles.none, ConsoleColor foreColour = ConsoleColor.White, ConsoleColor backColour = ConsoleColor.Black)
{
this.xPosition = x;
this.yPosition = y;
this.width = width;
this.height = height;
this.border = border;
this.foreColour = foreColour;
this.backColour = backColour;
bufferSize = height;
buffer = new string[bufferSize];
//fill the buffer with blank strings
for (int i = 0; i < bufferSize; i++)
buffer[i] = "";
}
public void WriteLine(string lineToWrite)
{
string[] newBuffer = new string[bufferSize]; //Create a new buffer into which we will copy our existing buffer
Array.Copy(buffer, 0, newBuffer, 1, bufferSize - 1); //Copy over the contents of the current buffer, cutting off the last entry and leaving the first entry clear.
newBuffer[0] = lineToWrite; //Write the new entry to the first element
buffer = newBuffer; //Copy the temporary buffer into the buffer variable
}
public override void DrawElement(ConsoleRenderer consoleRenderer)
{
if (border == BorderStyles.none) {
//no border, just draw the log.
WriteBuffer(0, consoleRenderer);
}
else {
//Draw a border before writing the text.
consoleRenderer.DrawBox(xPosition, yPosition, width, height, border, foreColour, backColour);
WriteBuffer(1, consoleRenderer);
}
}
private void WriteBuffer(int borderOffset, ConsoleRenderer consoleRenderer)
{
int tempWidth = width - (borderOffset * 2);
int tempHeight = height - (borderOffset * 2);
int tempX = xPosition + borderOffset;
int tempY = yPosition + borderOffset;
int linesRemaining = tempHeight;
int charsPerLine = tempWidth;
for (int currentString = 0; currentString < bufferSize; currentString++) {
if (linesRemaining > 0) {
//For each line, calculate how many lines it will take up in the logbox.
int numberOfLines = (int)Math.Ceiling((double)buffer[currentString].Length / (double)charsPerLine);
if (numberOfLines < 2) {
//We only need to write one line; simple!
consoleRenderer.WriteString(tempX, tempY + (linesRemaining - 1), buffer[currentString], foreColour, backColour);
linesRemaining--;
}
else {
//This is where it gets awkward. We need to account for text wrapping.
//To do this we split up the string into several substrings that will fit in the Log Box.
string[] substringArray = new string[numberOfLines];
for (int c = 0; c < numberOfLines - 1; c++) {
substringArray[c] = buffer[currentString].Substring(c * charsPerLine, charsPerLine);
}
substringArray[numberOfLines - 1] = buffer[currentString].Substring((numberOfLines - 1) * charsPerLine); //The last substring must go to the end of the string.
//Now, add each substring to the buffer and update the linesRemaining variable.
for (int c = numberOfLines - 1; c >= 0; c--) {
if (linesRemaining > 0) {
consoleRenderer.WriteString(tempX, tempY + (linesRemaining - 1), substringArray[c], foreColour, backColour);
linesRemaining--;
}
}
}
}
}
}
public override void DeleteElement()
{
throw new NotImplementedException();
}
public override string Interact()
{
//Console.ReadLine();
return "";
}
public override void Update()
{
}
}
#endregion
#region Picture Box
/// <summary>
/// A structure used to store image data, such as ASCII art or a game map.
/// </summary>
public struct Image
{
public int width;
public int height;
public char[] imageData;
public int[] imageColour;
public int[] imageBackColour;
}
public class PictureBox : Element
{
Image image; //stores the image to be rendered in the format [character] [colour]
int imageX; //The x position of the area of the image being rendered
int imageY; //The y position of the area of the image being rendered
int zoomLevel; //How 'far out' the image is zoomed, e.g. 1 = actual size, 2 = 50%, 4 = 25% etc.
public PictureBox(int x, int y, int width, int height, BorderStyles border = BorderStyles.none, ConsoleColor foreColour = ConsoleColor.White, Image image = new Image())
{
this.xPosition = x;
this.yPosition = y;
this.width = width;
this.height = height;
this.border = border;
this.foreColour = foreColour;
this.image = image;
imageX = 0;
imageY = 0;
}
public override void DrawElement (ConsoleRenderer consoleRenderer)
{
if (border == BorderStyles.none) {
DrawImage (0, consoleRenderer);
} else {
consoleRenderer.DrawBox (xPosition, yPosition, width, height, border, foreColour, ConsoleColor.Black);
DrawImage (1, consoleRenderer);
}
}
private void DrawImage(int borderOffset, ConsoleRenderer consoleRenderer)
{
int imageBufferSize = image.width * image.height;
for (int posX = xPosition + borderOffset; posX < width - borderOffset; posX++) {
for (int posY = yPosition + borderOffset; posY < height - borderOffset; posY++) {
try {
char charToWrite = image.imageData[(image.width * (posY + imageY)) + (posX + imageX)];
ConsoleColor colourToWrite = (ConsoleColor)image.imageColour[(image.width * (posY + imageY)) + (posX + imageX)];
ConsoleColor backColourToWrite = (ConsoleColor)image.imageBackColour[(image.width * (posY + imageY)) + (posX + imageX)];
consoleRenderer.WriteString(posX, posY, charToWrite.ToString(), colourToWrite, backColourToWrite);
} catch {
consoleRenderer.WriteString (posX, posY, " ", ConsoleColor.Black, ConsoleColor.Black);
}
}
}
}
public override void DeleteElement ()
{
throw new NotImplementedException ();
}
public override string Interact ()
{
throw new NotImplementedException ();
}
public override void Update ()
{
throw new NotImplementedException ();
}
}
#endregion
}
}