1 // =================================
  2 // Copyright (c) 2022 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 using System;
  7 
  8 namespace System.Screen
  9 {
 10     public class TextBoxCreateParams
 11     {
 12         public nothrow TextBoxCreateParams() : controlCreateParams()focusedForeColor(ConsoleColor.defaultColor)focusedBackColor(ConsoleColor.defaultColor)
 13         {
 14         }
 15         public TextBoxCreateParams& Defaults()
 16         {
 17             return *this;
 18         }
 19         public nothrow TextBoxCreateParams& SetLocation(const Point& loc)
 20         {
 21             controlCreateParams.SetLocation(loc);
 22             return *this;
 23         }
 24         public nothrow TextBoxCreateParams& SetSize(const Size& size_)
 25         {
 26             controlCreateParams.SetSize(size_);
 27             return *this;
 28         }
 29         public nothrow TextBoxCreateParams& SetForeColor(ConsoleColor foreColor_)
 30         {
 31             controlCreateParams.SetForeColor(foreColor_);
 32             return *this;
 33         }
 34         public nothrow TextBoxCreateParams& SetBackColor(ConsoleColor backColor_)
 35         {
 36             controlCreateParams.SetBackColor(backColor_);
 37             return *this;
 38         }
 39         public nothrow TextBoxCreateParams& SetText(const string& text_)
 40         {
 41             text = ToUtf32(text_);
 42             return *this;
 43         }
 44         public nothrow TextBoxCreateParams& SetFocusedForeColor(ConsoleColor focusedForeColor_)
 45         {
 46             focusedForeColor = focusedForeColor_;
 47             return *this;
 48         }
 49         public nothrow TextBoxCreateParams& SetFocusedBackColor(ConsoleColor focusedBackColor_)
 50         {
 51             focusedBackColor = focusedBackColor_;
 52             return *this;
 53         }
 54         public ControlCreateParams controlCreateParams;
 55         public ustring text;
 56         public ConsoleColor focusedForeColor;
 57         public ConsoleColor focusedBackColor;
 58     }
 59     
 60     public class TextBox : Control
 61     {
 62         public nothrow TextBox(TextBoxCreateParams& createParams) : 
 63             base(createParams.controlCreateParams)
 64             text()
 65             pos(0)
 66             focusedForeColor(createParams.focusedForeColor)
 67             focusedBackColor(createParams.focusedBackColor)
 68         {
 69             InvalidateGuard invalidateGuard(thisInvalidateKind.dontInvalidate);
 70             if (ForeColor() == ConsoleColor.defaultColor)
 71             {
 72                 SetForeColor(ConsoleColor.gray);
 73             }
 74             if (BackColor() == ConsoleColor.defaultColor)
 75             {
 76                 SetBackColor(ConsoleColor.black);
 77             }
 78             if (focusedForeColor == ConsoleColor.defaultColor)
 79             {
 80                 focusedForeColor = ConsoleColor.white;
 81             }
 82             if (focusedBackColor == ConsoleColor.defaultColor)
 83             {
 84                 focusedBackColor = ConsoleColor.darkBlue;
 85             }
 86             SetCursorPos();
 87         }
 88         public void SetText(const ustring& text_)
 89         {
 90             if (text != text_)
 91             {
 92                 text = text_;
 93                 OnTextChanged();
 94                 Invalidate();
 95             }
 96         }
 97         public void SetText(const string& text_)
 98         {
 99             SetText(ToUtf32(text_));
100         }
101         public nothrow const ustring& Text() const
102         {
103             return text;
104         }
105         public override void OnWriteScreen(WriteScreenEventArgs& args)
106         {
107             base->OnWriteScreen(args);
108             Rect updateRect = GetRect();
109             if (!args.GetRect().IsDefault())
110             {
111                 updateRect = Rect.Intersection(updateRectargs.GetRect());
112             }
113             if (updateRect.IsEmpty()) return;
114             Clear(updateRectForeColor()BackColor());
115             ConsoleColor foreColor = ForeColor();
116             ConsoleColor backColor = BackColor();
117             if (IsFocused())
118             {
119                 foreColor = focusedForeColor;
120                 backColor = focusedBackColor;
121             }
122             Clear(updateRectforeColorbackColor);
123             Point cp = Location();
124             SetCursorPos(cp.xcp.y);
125             if (text.Length() < updateRect.size.w)
126             {
127                 Terminal.Out() << text;
128             }
129             else
130             {
131                 int startPos = StartPos();
132                 ustring txt = text.Substring(startPosupdateRect.size.w);
133                 Terminal.Out() << txt;
134             }
135             SetCursorPos();
136         }
137         public override void OnKeyPressed(KeyEventArgs& args)
138         {
139             base->OnKeyPressed(args);
140             if (IsEnabled() && !args.Handled())
141             {
142                 int prevStartPos = StartPos();
143                 uchar key = args.Key();
144                 if (key < specialKeyStart)
145                 {
146                     if (key == keyNewline)
147                     {
148                         args.SetHandled();
149                         OnTextEntered();
150                     }
151                     else if (key == keyBackspace)
152                     {
153                         args.SetHandled();
154                         if (pos > 0)
155                         {
156                             CursorLeft(prevStartPos);
157                             DeleteChar();
158                         }
159                     }
160                     else
161                     {
162                         if (key >= ' ' && key < specialKeyStart)
163                         {
164                             args.SetHandled();
165                             InsertChar(key);
166                         }
167                     }
168                 }
169                 else
170                 {
171                     switch (key)
172                     {
173                         case keyDel:
174                         {
175                             args.SetHandled();
176                             DeleteChar();
177                             break;
178                         }
179                         case keyLeft:
180                         {
181                             args.SetHandled();
182                             CursorLeft(prevStartPos);
183                             break;
184                         }
185                         case keyRight:
186                         {
187                             args.SetHandled();
188                             CursorRight(prevStartPos);
189                             break;
190                         }
191                         case keyHome:
192                         {
193                             args.SetHandled();
194                             CursorToStart(prevStartPos);
195                             break;
196                         }
197                         case keyEnd:
198                         {
199                             args.SetHandled();
200                             CursorToEnd(prevStartPos);
201                             break;
202                         }
203                     }
204                 }
205             }
206         }
207         public virtual void OnTextChanged()
208         {
209             textChangedEvent.Fire();
210         }
211         public virtual void OnTextEntered()
212         {
213             textEnteredEvent.Fire();
214         }
215         public nothrow Event<ChangedEventHandler>& TextChangedEvent()
216         {
217             return textChangedEvent;
218         }
219         public nothrow Event<SelectEventHandler>& TextEnteredEvent()
220         {
221             return textEnteredEvent;
222         }
223         private int StartPos()
224         {
225             Rect rect = GetRect();
226             return Max(cast<int>(0)cast<int>(pos - rect.size.w));
227         }
228         private void CursorLeft(int prevStartPos)
229         {
230             if (pos > 0)
231             {
232                 --pos;
233                 SetCursorPos();
234                 if (StartPos() != prevStartPos)
235                 {
236                     Invalidate(GetRect());
237                 }
238             }
239         }
240         private void CursorRight(int prevStartPos)
241         {
242             if (pos < text.Length())
243             {
244                 ++pos;
245                 SetCursorPos();
246                 if (StartPos() != prevStartPos)
247                 {
248                     Invalidate(GetRect());
249                 }
250             }
251         }
252         private void CursorToStart(int prevStartPos)
253         {
254             if (pos != 0)
255             {
256                 pos = 0;
257                 SetCursorPos();
258                 if (StartPos() != prevStartPos)
259                 {
260                     Invalidate(GetRect());
261                 }
262             }
263         }
264         private void CursorToEnd(int prevStartPos)
265         {
266             if (pos != text.Length())
267             {
268                 pos = cast<int>(text.Length());
269                 SetCursorPos();
270                 if (StartPos() != prevStartPos)
271                 {
272                     Invalidate(GetRect());
273                 }
274             }
275         }
276         private void DeleteChar()
277         {
278             if (pos < text.Length())
279             {
280                 text.Remove(pos1);
281                 OnTextChanged();
282                 Invalidate(GetRect());
283             }
284         }
285         private void InsertChar(uchar ch)
286         {
287             if (pos < text.Length())
288             {
289                 text.Insert(posch);
290                 ++pos;
291                 OnTextChanged();
292                 Invalidate(GetRect());
293             }
294             else
295             {
296                 text.Append(ch);
297                 ++pos;
298                 OnTextChanged();
299                 Invalidate(GetRect());
300             }
301         }
302         private void SetCursorPos()
303         {
304             Point cp = Location();
305             cp.x = cp.x + pos;
306             SetControlCursorPos(cp);
307             SetCursorPos(cp.xcp.y);
308         }
309         private ustring text;
310         private int pos;
311         private int startPos;
312         private Event<ChangedEventHandler> textChangedEvent;
313         private Event<SelectEventHandler> textEnteredEvent;
314         private ConsoleColor focusedForeColor;
315         private ConsoleColor focusedBackColor;
316     }
317 }