forked from Hezkore/m2terminimal
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathm2terminimal.monkey2
371 lines (297 loc) · 7.21 KB
/
m2terminimal.monkey2
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
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
Namespace m2terminimal
#Import "<std>"
Using std..
#If __TARGET__="windows"
#Import "native/windows"
#ElseIf __TARGET__="linux"
#ElseIf __TARGET__="macos"
#Endif
Global Console:=New ConsoleHandler
Enum AnsiColor
Black=30,Red,Green,Yellow,Blue,Magenta,Cyan,White
End
Class ConsoleHandler
Struct Char
Field _code:UInt
Field _fg:Int
Field _bg:Int
End
Struct InputKey
Field Code:UInt
Field State:KeyState
Method Ascii:String()
If Code=32 Then Return " "
If Code>=65 And Code<=90 Then
If State & KeyState.Capslock Or State & KeyState.Shift Then
Return String.FromChar( Code )
Else
Return String.FromChar( Code+32 )
Endif
Endif
Return ""
End
End
Enum KeyState
Capslock=$0080
Enhanced=$0100
LeftAlt=$0002
LeftCtrl=$0008
Numlock=$0020
RightAlt=$0001
RightCtrl=$0004
Scrolllock=$0040
Shift=$0010
End
Method New()
InitConsole( Self )
UpdateSize()
End
Property CursorVisible:Bool()
Return _curVisible
Setter( visible:Bool )
_curVisible=visible
End
Property Color:Int()
Return _color
Setter( color:Int )
_color=color
End
Property Background:Int()
Return _background
Setter( background:Int )
_background=background
End
Method Alert( msg:String, error:Bool=False, char:Int=176 )
If error Then
msg="ERROR "+msg
Else
msg="ALERT "+msg
Endif
Print msg
native_cursorposition=New Vec2i(0,0)
For Local x:Int=0 To _bufferWidth
native_plot(char)
Next
native_cursorposition=New Vec2i(_bufferWidth/2-msg.Length/2,0)
For Local x:Int=0 Until msg.Length
native_plot(msg[x])
Next
Local delay:=Millisecs()+2500
Repeat
If Not error And Millisecs()>delay Then
Exit
Endif
Forever
For Local x:Int=0 Until _bufferWidth
If x>=_frontBuffer.Length Then Exit
_frontBuffer[x]._code=char
Next
End
Method Size:Vec2i()
Return New Vec2i( _bufferWidth, _bufferHeight )
End
Method UpdateSize()
Local w:=native_windowsize.X+1
Local h:=native_windowsize.Y+1
If _bufferWidth=w And _bufferHeight=h Then Return
_bufferWidth=w
_bufferHeight=h
If _frontBuffer.Length>0 Then native_clear()
_backBuffer=_backBuffer.Resize( _bufferHeight*_bufferWidth )
_frontBuffer=New Char[_backBuffer.Length]
_lastBackBuffer=New Char[_backBuffer.Length]
End
Method TranslatePos:Int( x:Int, y:Int )
If y>=_bufferHeight Then y=_bufferHeight-1
Return (y*_bufferWidth)+x
End
Method Input( text:String, x:Float, y:Float )
Local asc:String
CursorPosition=New Vec2i( x+text.Length+_inputText.Length-_inputCursor, y )
CursorVisible=True
For Local k:=Eachin _keysHit
' Backspace
If k.Code=8 And _inputText.Length-_inputCursor>0 Then
If _inputCursor Then
_inputText=_inputText.Left( _inputText.Length-_inputCursor-1 )+_inputText.Right( _inputCursor )
Else
_inputText=_inputText.Slice( 0, -1 )
Endif
Continue
Endif
' Delete
If k.Code=46 And _inputCursor Then
If _inputCursor>1 Then
_inputText=_inputText.Left( _inputText.Length-_inputCursor )+_inputText.Right( _inputCursor-1 )
Else
_inputText=_inputText.Slice( 0, -1 )
Endif
_inputCursor-=1
Continue
Endif
' Left
If k.Code=37 Then
If _inputCursor<_inputText.Length Then _inputCursor+=1
Continue
Endif
' Right
If k.Code=39 Then
If _inputCursor>0 Then _inputCursor-=1
Continue
Endif
asc=k.Ascii()
If asc Then
If _inputCursor Then
_inputText=_inputText.Left( _inputText.Length-_inputCursor )+asc+_inputText.Right( _inputCursor )
Else
_inputText+=asc
Endif
Continue
Endif
Next
If _inputCursor>_inputText.Length Then _inputCursor=_inputText.Length
DrawText( text+_inputText, x, y )
End
Property CursorPosition:Vec2i()
Return _curPos
Setter( pos:Vec2i )
If pos<>_curPos Then _curPos=pos
End
Method DrawText( text:String, x:Float, y:Float )
' Will the text even be visible?
If text.Length<=0 Then Return
If x+text.Length<0 Or x>=_bufferWidth Then Return
If y<0 Or y>=_bufferHeight Then Return
For Local i:=0 Until text.Length
If x<0 Then
x+=1
Continue
Else
If x>=_bufferWidth Then Exit
Endif
Plot( text[i], x, y )
x+=1
Next
End
Method DrawRect( x:Float, y:Float, width:Int, height:Int, char:Int=219 )
If width=0 Or height=0 Then Return
For Local dy:=y Until y+height
For Local dx:=x Until x+width
If dx<0 Or dx>=_bufferWidth Then Continue
If dy<0 Or dy>=_bufferHeight Then Continue
Plot( char, dx, dy )
Next
Next
End
Method Plot( charCode:UInt, x:Float, y:Float )
Local pos:Int=TranslatePos( x, y )
_backBuffer[pos]._code=charCode
_backBuffer[pos]._fg=_color
_backBuffer[pos]._bg=_background
End
Method Clear()
For Local i:=0 Until _backBuffer.Length
_backBuffer[i]._code=0
_backBuffer[i]._fg=AnsiColor.White
_backBuffer[i]._bg=AnsiColor.Black
Next
End
Method KeyHit:Bool( key:Int )
For Local k:=Eachin _keysHit
If k.Code=key Then Return True
Next
Return False
End
Method KeyDown:Bool( key:Int )
For Local k:=Eachin _keysDown
If k.Code=key Then Return True
Next
Return False
End
Method Render()
' Do we even need to redraw?
Local needsRedraw:Bool=False
For Local i:=0 Until _backBuffer.Length
If _backBuffer[i]<>_lastBackBuffer[i] Then
needsRedraw=True
_diffFrames+=1
Exit
Endif
Next
' Do not need redraw
If Not needsRedraw Then
_sameFrames+=1
Return
Endif
' Needs redraw
Local x:Int
Local y:Int
native_cursorvisible=False
For Local i:=0 Until _backBuffer.Length
_lastBackBuffer[i]=_backBuffer[i]
If x>=_bufferWidth Then
x=0
y+=1
Endif
If _backBuffer[i]<>_frontBuffer[i] Then
native_cursorposition=New Vec2i( x, y )
If _lastColor<>_backBuffer[i]._fg Or _lastBackground<>_backBuffer[i]._bg Then
_lastColor=_backBuffer[i]._fg
_lastBackground=_backBuffer[i]._bg
native_color( _lastColor, _lastBackground )
Endif
native_plot( _backBuffer[i]._code )
_frontBuffer[i]=_backBuffer[i]
Endif
x+=1
Next
If _curVisible Then
native_cursorvisible=True
If native_cursorposition<>_curPos Then
native_cursorposition=_curPos
Endif
Endif
End
Method UpdateEvents()
_keysHit.Clear()
native_input()
End
Private
Field _lastBackBuffer:Char[]
Field _backBuffer:Char[]
Field _frontBuffer:Char[]
Field _bufferWidth:Int
Field _bufferHeight:Int
Field _curVisible:Bool'=True
Field _curPos:Vec2i
Field _keysHit:=New Stack<InputKey>
Field _keysDown:=New Stack<InputKey>
Field _sameFrames:UInt
Field _diffFrames:UInt
Field _inputText:String
Field _inputCursor:UInt
Field _color:Int=AnsiColor.White
Field _lastColor:Int
Field _background:Int=AnsiColor.Blue
Field _lastBackground:Int
Public
Method _AddKeyHit( key:UInt, state:KeyState )
Local k:=New InputKey
k.Code=key
k.State=state
_keysHit.Add( k )
End
Method _AddKeyDown( key:UInt, state:KeyState )
Local k:=New InputKey
k.Code=key
k.State=state
_keysDown.Add( k )
End
Method _RemoveKeyDown( key:UInt )
For Local i:=0 Until _keysDown.Length
If _keysDown[i].Code=key Then
_keysDown.Erase( i )
Endif
Next
End
End