1
+ import tkinter as tk
2
+ import threading
3
+
4
+ RED = "#ff0000"
5
+ GREEN = "#00ff00"
6
+ BLUE = "#0000ff"
7
+ BLACK = "#000000"
8
+ WHITE = "#ffffff"
9
+ DARKBG = "#2b2b2b"
10
+ LIGHTBG = "#3c3f41"
11
+ TEXTCOLOR = "#b5b5b5"
12
+
13
+ class VirtualTerminal (object ):
14
+ def __init__ (self , startfunction = None , enterfunction = None ):
15
+ self .terminal_bgColor = DARKBG
16
+ self .terminal_textColor = TEXTCOLOR
17
+ self .terminal_insertColor = TEXTCOLOR
18
+
19
+ self .input_bgColor = DARKBG
20
+ self .input_textColor = TEXTCOLOR
21
+ self .input_insertColor = TEXTCOLOR
22
+
23
+ self .divider_height = 1
24
+ self .divider_color = LIGHTBG
25
+
26
+ self .terminal_font = ("Menlo-Regular.ttf" , 19 )
27
+ self .input_font = ("Menlo-Regular.ttf" , 19 )
28
+ self .title = "VTerminal"
29
+ self .size = (700 , 410 )
30
+
31
+ self .resizable = (True , True )
32
+
33
+ self .root = tk .Tk ()
34
+ self .position = (int ((self .root .winfo_screenwidth () / 2 ) - (self .size [0 ] / 2 )), int ((self .root .winfo_screenheight () / 2 ) - (self .size [1 ] / 2 )))
35
+
36
+
37
+
38
+ self .root .geometry (f"{ self .size [0 ]} x{ self .size [1 ]} +{ self .position [0 ]} +{ self .position [1 ]} " )
39
+
40
+
41
+
42
+ self .root .title (self .title )
43
+
44
+ self .root .resizable (self .resizable [0 ], self .resizable [1 ])
45
+
46
+
47
+ self .mainFrame = tk .Frame (self .root , bg = DARKBG )
48
+ self .mainFrame .pack (expand = 1 , fill = "both" )
49
+
50
+ self .terminalFrame = tk .Frame (self .mainFrame , bg = DARKBG )
51
+ self .terminalFrame .pack (expand = 1 , fill = "both" )
52
+
53
+ self .terminalDisplay = tk .Text (self .terminalFrame , bg = self .terminal_bgColor , insertbackground = self .terminal_insertColor , fg = self .terminal_textColor , height = 1 , highlightthickness = 0 ,
54
+ borderwidth = 2 ,
55
+ relief = "flat" , font = self .terminal_font )
56
+ self .terminalDisplay .pack (expand = 1 , fill = "both" )
57
+
58
+ self .terminalDisplay .bind ("<Key>" , lambda test : "break" )
59
+
60
+ self .divider = tk .Frame (self .mainFrame , bg = self .divider_color , height = 1 )
61
+ self .divider .pack (fill = "x" )
62
+
63
+ self .inputFrame = tk .Frame (self .mainFrame , bg = DARKBG , height = 40 )
64
+ self .inputFrame .pack (fill = "x" , side = "bottom" )
65
+
66
+ self .inputEntry = tk .Entry (self .inputFrame , bg = self .input_bgColor , relief = "flat" , fg = self .input_textColor , borderwidth = 2 , insertbackground = self .input_insertColor , highlightthickness = 0 , font = self .input_font )
67
+ self .inputEntry .pack (expand = 1 , fill = "both" )
68
+
69
+ # Can't do right now (on mac)
70
+ # inputButton = tk.Button(inputFrame, text="Enter", relief="flat")
71
+ # inputButton.pack(side="right")
72
+
73
+ self .start_function = startfunction
74
+ self .enter_function = enterfunction
75
+
76
+ self .inputEntry .bind ("<Return>" , self .enter_pressed )
77
+
78
+ self .asking = False
79
+ self .answer = None
80
+
81
+
82
+
83
+ def update_config (self ):
84
+ self .terminalDisplay .config (bg = self .terminal_bgColor ,
85
+ fg = self .terminal_textColor ,
86
+ insertbackground = self .terminal_insertColor ,
87
+ font = self .terminal_font )
88
+
89
+ self .inputEntry .config (bg = self .input_bgColor ,
90
+ fg = self .input_insertColor ,
91
+ insertbackground = self .input_insertColor ,
92
+ font = self .input_font )
93
+
94
+ self .root .title (self .title )
95
+ self .root .geometry (f"{ self .size [0 ]} x{ self .size [1 ]} +{ self .position [0 ]} +{ self .position [1 ]} " )
96
+ self .root .resizable (self .resizable [0 ], self .resizable [1 ])
97
+ self .divider .config (height = self .divider_height , bg = self .divider_color )
98
+
99
+
100
+
101
+
102
+ def enter_pressed (self , event ):
103
+ text = self .inputEntry .get ()
104
+ if self .asking :
105
+ self .answer = text
106
+ self .asking = False
107
+ self .inputEntry .delete (0 , "end" )
108
+ if self .enter_function :
109
+ self .enter_function (text )
110
+
111
+ def bind_input (self , function ):
112
+ self .enter_function = function
113
+ # self.inputEntry.bind("<Return>", lambda e: function(self.inputEntry.get()))
114
+
115
+ def bind_start (self , function ):
116
+ self .start_function = function
117
+
118
+
119
+ def get_terminal (self ):
120
+ text = self .terminalDisplay .get (1.0 , "end" )
121
+ return text [:len (text ) - 1 ]
122
+
123
+ def set_terminal (self , text ):
124
+ self .terminalDisplay .delete (1.0 , "end" )
125
+ self .terminalDisplay .insert (1.0 , text )
126
+
127
+ def rgb2hex (self , rgb ):
128
+ return '#%02x%02x%02x' % rgb
129
+
130
+
131
+ def config_terminal (self , bgcolor = None , textcolor = None , fontpath = None , fontsize = None ):
132
+ if bgcolor :
133
+ if isinstance (bgcolor , tuple ):
134
+ self .terminal_bgColor = self .rgb2hex (bgcolor )
135
+ else :
136
+ self .terminal_bgColor = bgcolor
137
+
138
+
139
+ if textcolor :
140
+ if isinstance (textcolor , tuple ):
141
+ self .terminal_textColor = self .rgb2hex (textcolor )
142
+ else :
143
+ self .terminal_textColor = textcolor
144
+
145
+ if fontpath :
146
+ self .terminal_font = (fontpath , self .terminal_font [1 ])
147
+
148
+ if fontsize :
149
+ self .terminal_font = (self .terminal_font [0 ], fontsize )
150
+
151
+ self .update_config ()
152
+
153
+ def config_input (self , bgcolor = None , textcolor = None , fontpath = None , fontsize = None ):
154
+ if bgcolor :
155
+ if isinstance (bgcolor , tuple ):
156
+ self .input_bgColor = self .rgb2hex (bgcolor )
157
+ else :
158
+ self .input_bgColor = bgcolor
159
+
160
+ if textcolor :
161
+ if isinstance (textcolor , tuple ):
162
+ self .input_textColor = self .rgb2hex (textcolor )
163
+ else :
164
+ self .input_textColor = textcolor
165
+
166
+ if fontpath :
167
+ self .input_font = (fontpath , self .input_font [1 ])
168
+
169
+ if fontsize :
170
+ self .input_font = (self .input_font [0 ], fontsize )
171
+
172
+ self .update_config ()
173
+
174
+ def config_window (self , title = None , size = None , position = None , resizable = None , dividercolor = None , dividerheight = None ):
175
+ if title :
176
+ self .title = title
177
+ if size :
178
+ self .size = size
179
+
180
+ if position :
181
+ self .position = position
182
+
183
+ if resizable :
184
+ self .resizable = resizable
185
+
186
+ if dividercolor :
187
+ if isinstance (dividercolor , tuple ):
188
+ self .divider_color = self .rgb2hex (dividercolor )
189
+ else :
190
+ self .divider_color = dividercolor
191
+
192
+ if dividerheight :
193
+ self .divider_height = dividerheight
194
+
195
+ self .update_config ()
196
+
197
+ def print (self , text , end = "\n " ):
198
+ self .set_terminal (self .get_terminal () + text + end )
199
+
200
+
201
+ def input (self ):
202
+ self .asking = True
203
+
204
+ while not self .answer :
205
+ pass
206
+ self .answer = None
207
+
208
+ return self .answer
209
+
210
+
211
+
212
+ def cancel_input (self ):
213
+ self .asking = False
214
+
215
+
216
+ def mainloop (self ):
217
+ if self .start_function :
218
+ threading .Thread (target = self .start_function ).start ()
219
+ self .root .mainloop ()
0 commit comments