Прикреплённый файл «pyginput.py»
Загрузка 1 #!/usr/bin/env python
2 # coding: utf
3 '''
4 Simple input box for pygame
5
6 Usage:
7 box=Input(…) # declare an input box
8 while <main loop>:
9 …
10 if box.is_active() and <event goes to box>: # currently in input state
11 box.edit(event) # pass event to the box
12 else:
13 <parse eventsd normally>
14 …
15 if box.is_done(): # input is finished …
16 if box.is_cancelled(): # …with cancel
17 <"no input is needed" action>
18 elif box.is_failed(): # …unsuccessfully
19 <unsuccessfull input action>
20 else: # …succsessfuly
21 <succsessful input action>
22 box.deactivate() # hide box and resore state
23 …
24 if <input is needed>: # we need to input something in program
25 box.activate(…) # store old state and turn on the box
26 …
27 if box.is_active(): box.draw(surface,pos) # show box after all surface changes
28 pygame.display.flip() # display the picture
29 if box.is_active(): box.undraw() # hide box before further surface changes
30 '''
31
32 import pygame
33 __VERSION__=0.06
34
35 ACTIVE,DONE,FAILED,CANCEL,SHOWN,FIRST=(1<<i for i in range(6))
36
37 _unicode=type(u"")
38
39 class Input:
40 # Default values for some properties
41 BorderWidth=3
42 Status=0
43 CursorWidth=2
44 Margin=0
45 TextColor=pygame.Color("Black")
46 PromptColor=pygame.Color("grey50")
47 CursorColor=pygame.Color("grey75")
48 OverColor=pygame.Color("tomato")
49 PaperColor=pygame.Color("ivory")
50 Prompt=u""
51 DefaultText=u""
52 SetType=_unicode
53 RetryIncorrect=True
54 TextLength=8
55 FontID=None
56 Font=None
57 FontSize=24
58 PromptGap=None
59 Size=None
60 FixedSize=False
61 BackingStore=None
62 RepeatStore=None
63 RepeatDefault=(500,100)
64
65 def __update__(self, *pargs, **nargs):
66 '''Update box properties.
67 Positional parameters: [Prompt, [DefaultText]].
68 Named parameters: all class data fields.
69
70 - Size supercedes FontSize, default FontSize is 24
71 - setting DefaultText also sets SetType (so use 0., not "0" for float input)
72 '''
73 if len(pargs)>0:
74 self.Prompt=pargs[0]
75 if len(pargs)>1:
76 self.DefaultText=_unicode(pargs[1])
77 self.SetType=type(pargs[1])
78 for prop in nargs:
79 if hasattr(self,prop):
80 setattr(self,prop,nargs[prop])
81 if not self.FontID:
82 self.FontID=pygame.font.match_font("sans")
83 if self.PromptGap is None and self.Prompt:
84 self.PromptGap=" "
85 if "SetType" not in nargs and "DefaultText" in nargs:
86 self.SetType=type(nargs["DefaultText"])
87 if "TextLength" not in nargs and self.DefaultText:
88 self.TextLength=0
89 if "Size" in nargs:
90 self.FixedSize=True
91 self.FontSize=self.Size[1]-2*self.BorderWidth
92 self.Font=pygame.font.Font(self.FontID, self.FontSize)
93 elif not self.Size or not self.FixedSize:
94 self.Font=pygame.font.Font(self.FontID, self.FontSize)
95 self.Size=self.Font.size(self.Prompt+self.PromptGap+"W"*max(self.TextLength,len(self.DefaultText)+1,2))
96 self.Size=self.Size[0]+2*self.BorderWidth,self.Size[1]+2*self.BorderWidth
97 self.Paper=pygame.Surface(self.Size)
98 # TODO background image/transparency for Paper
99 self.Paper.fill(self.PaperColor)
100 pr=self.Font.render(self.Prompt, True, self.PromptColor)
101 self.Paper.blit(pr, (self.BorderWidth,(self.Size[1]-pr.get_height())//2))
102 self.Text=_unicode(self.DefaultText)
103 self.Cursor=len(self.Text)
104
105 def __init__(self, *pargs, **nargs):
106 '''Create a text input entity. Call __update__() next.'''
107 self.__update__(*pargs, **nargs)
108
109 def __sawtoothed__(self, block, side, mult=3):
110 '''Create a sawtoothed mark for left (False) or right (True) side'''
111 w,h=block.get_size()
112 nw=mult*self.BorderWidth
113 n=(h//nw)|1
114 x,d=side and (w-1,-nw) or (0,nw)
115 return [(x+d*(i%2),h*i//n) for i in range(n)]
116
117 def value(self):
118 '''Check if input is correct and return it, return None if it is not'''
119 try:
120 return self.SetType(self.Text)
121 except:
122 try:
123 return self.SetType(str(self.Text))
124 except:
125 return None
126
127 def render(self):
128 '''Return paper surface with current prompt and text printed on'''
129 ret=self.Paper.copy()
130 wl=self.Font.size(self.Prompt+self.PromptGap)[0]
131 ib=ret.subsurface((wl,0,ret.get_width()-wl,ret.get_height()))
132 ia=ret.subsurface((wl+self.BorderWidth,self.BorderWidth,ret.get_width()-wl-2*self.BorderWidth,ret.get_height()-2*self.BorderWidth))
133 pr=self.Font.render(self.Text, True, self.TextColor)
134 w=self.Font.size(self.Text[:self.Cursor])[0]
135 while self.Margin and w-self.Font.size(self.Text[:self.Margin])[0]<self.CursorWidth and self.Margin>0:
136 self.Margin-=1
137 while w-self.Font.size(self.Text[:self.Margin])[0]>ia.get_width()-self.CursorWidth and self.Margin<len(self.Text):
138 self.Margin+=1
139 Offset=-self.Font.size(self.Text[:self.Margin])[0]
140 ia.blit(pr,(Offset,(ia.get_height()-pr.get_height())//2))
141 pygame.draw.line(ia, self.CursorColor, (w+Offset,2), (w+Offset,ia.get_height()-2),self.CursorWidth)
142 if Offset<0:
143 pygame.draw.polygon(ib, self.OverColor, self.__sawtoothed__(ib, False))
144 if Offset+pr.get_width()>ia.get_width()-self.CursorWidth:
145 pygame.draw.polygon(ib, self.OverColor, self.__sawtoothed__(ib, True))
146 return ret
147
148 def draw(self,scr,pos):
149 '''Draw input box on surface scr at position pos
150 backuping an underlying part of surface'''
151 self.BackingStore=(self.Paper.copy(),scr,pos)
152 self.BackingStore[0].blit(self.BackingStore[1],(0,0),(self.BackingStore[2],self.Size))
153 self.BackingStore[1].blit(self.render(),self.BackingStore[2])
154 self.Status|=SHOWN
155
156 def undraw(self):
157 '''Remove the box from the surface it was drawn
158 restoring underlying part of surface'''
159 if self.BackingStore:
160 self.BackingStore[1].blit(self.BackingStore[0],self.BackingStore[2])
161 self.Status&=~SHOWN
162
163 def activate(self, *pargs, **nargs):
164 '''Enable input from the box.
165 If either pargs or nargs is given, call __update__().
166 Return False if no activation was needed, True otherwise.
167
168 Calling __update__() means resetting every field,
169 so use `inputbox.activate("<any prompt>")' to replace
170 last entered value with the default one.
171 '''
172 if self.Status&ACTIVE and not pargs and not nargs:
173 return False
174 if pargs or nargs:
175 self.__update__(*pargs, **nargs)
176 self.Cursor=len(self.Text)
177 self.Margin=0
178 self.Status=ACTIVE|FIRST
179 self.RepeatStore=pygame.key.get_repeat()
180 pygame.key.set_repeat(*self.RepeatDefault)
181 return True
182
183 def deactivate(self):
184 '''Disable input from the box'''
185 if self.Status:
186 self.Status=0
187 pygame.key.set_repeat(*self.RepeatStore)
188
189 def is_active(self): return self.Status&ACTIVE
190 def is_done(self): return self.Status&DONE
191 def is_failed(self): return self.Status&FAILED
192 def is_cancelled(self): return self.Status&CANCEL
193 def is_shown(self): return self.Status&SHOWN
194
195 def is_success(self):
196 return self.is_done() and not (self.is_failed() or self.is_cancelled())
197
198 def edit(self,ev):
199 '''Proceed event for editing input box.
200 Supported keys:
201 <any unicode symbol>: input character
202 <Return>/<Enter>: finish input
203 <Backspace>/<Del>: delete character under/after the cursor
204 <Esc>: restore default value
205 <Home>/<End>/→/←: move cursor
206 <Esc><Esc>: cancel input'''
207 if ev.type is pygame.KEYDOWN:
208 if ev.key == pygame.K_BACKSPACE:
209 if self.Cursor>0:
210 self.Text=self.Text[:self.Cursor-1]+self.Text[self.Cursor:]
211 self.Cursor-=1
212 elif ev.key == pygame.K_DELETE:
213 if self.Cursor<len(self.Text):
214 self.Text=self.Text[:self.Cursor]+self.Text[self.Cursor+1:]
215 elif ev.unicode >= u' ':
216 if self.Status&FIRST:
217 self.Text=ev.unicode
218 self.Cursor=1
219 else:
220 self.Text=self.Text[:self.Cursor]+ev.unicode+self.Text[self.Cursor:]
221 self.Cursor+=1
222 elif ev.key == pygame.K_ESCAPE:
223 if self.Text==self.DefaultText:
224 self.Status|=CANCEL|DONE
225 self.Text=self.DefaultText
226 self.Margin=0
227 elif ev.key in (pygame.K_RETURN, pygame.K_KP_ENTER):
228 if self.value() is None:
229 if self.RetryIncorrect:
230 # TODO signal an error
231 self.Text=self.DefaultText
232 self.Margin=0
233 else:
234 self.Status|=DONE|FAILED
235 else:
236 self.Status|=DONE
237 elif ev.key == pygame.K_HOME:
238 self.Cursor=0
239 elif ev.key == pygame.K_END:
240 self.Cursor=len(self.Text)
241 elif ev.key == pygame.K_RIGHT:
242 self.Cursor=min(self.Cursor+1,len(self.Text))
243 elif ev.key == pygame.K_LEFT:
244 self.Cursor=max(self.Cursor-1,0)
245 self.Status&=~FIRST
246
247 def input(self, scr, pos, *pargs, **nargs):
248 '''Perform synchronous input on surface scr at position pos.
249 All unused events are ignored.'''
250 self.activate(*pargs, **nargs)
251 while not self.is_done():
252 self.edit(pygame.event.wait())
253 self.draw(scr,pos)
254 pygame.display.flip()
255 self.undraw()
256 self.deactivate()
257 return self.value()
258
259 def Print(scr, text, pos=None, font=None, size=24, antialias=True, color=None, background=None):
260 '''Print text on surface screen using as many defaults as possible'''
261 # TODO font is registered every time you print, fix this
262 f=pygame.font.Font(font, size)
263 if pos == None:
264 pos=scr.get_size()
265 sz=f.size(text)
266 pos=(pos[0]-sz[0])//2,(pos[1]-sz[1])//2
267 if color == None:
268 color=scr.get_at(pos)
269 color.r, color.g, color.b = 255^color.r, 255^color.g, 255^color.b
270 if background:
271 pr=f.render(text, antialias, color, background=background)
272 else:
273 pr=f.render(text, antialias, color)
274 scr.blit(pr, pos)
275
276 def __main():
277 import random
278 _=random.randint
279 pygame.init()
280 Size=(760,180)
281 Scr=pygame.display.set_mode(Size)
282 Scr.fill(pygame.Color("Black"))
283 r=20
284 x,y=Size[0]//12,Size[1]//5
285 inp=Input("Input",Size=(Size[0]-2*x,Size[1]-2*y))
286 cont,verbose=True,False
287 defaults,defcnt=(("String",u""),("Int",0),("Float",0.)),0
288 while cont:
289 pos=_(r,Size[0]-r),_(r,Size[1]-r)
290 col=_(10,255),_(10,255),_(10,255)
291 pygame.draw.circle(Scr,col,pos,r)
292 for ev in pygame.event.get():
293 if verbose:
294 print(ev)
295 if ev.type is pygame.QUIT:
296 cont=False
297 if ev.type is pygame.KEYDOWN and inp.is_active():
298 inp.edit(ev)
299 elif ev.type is pygame.KEYDOWN:
300 if ev.key in (pygame.K_KP_ENTER, pygame.K_RETURN, 13):
301 if not inp.is_active():
302 inp.activate(*defaults[defcnt])
303 defcnt=(defcnt+1)%len(defaults)
304 elif ev.key == pygame.K_F1:
305 verbose=True
306 elif ev.key is pygame.K_ESCAPE:
307 if not inp.is_active():
308 cont=False
309
310 if inp.is_done():
311 if inp.is_failed():
312 print("Data incorrect")
313 elif inp.is_cancelled():
314 print("Input is cancelled")
315 else:
316 print(u"Result: '{0}'".format(inp.value()))
317 inp.deactivate()
318
319 if inp.is_active(): inp.draw(Scr,(x,y))
320 pygame.display.flip()
321 if inp.is_active(): inp.undraw()
322 quit()
323
324 if __name__ == "__main__":
325 __main()
Прикреплённые файлы
Для ссылки на прикреплённый файл в тексте страницы напишите attachment:имяфайла, как показано ниже в списке файлов. Не используйте URL из ссылки «[получить]», так как он чисто внутренний и может измениться.- [получить | показать] (2017-08-13 18:17:03, 12.5 KB) [[attachment:pyginput.py]]
- [получить | показать] (2017-08-14 01:21:09, 2.1 KB) [[attachment:vector.py]]
Вам нельзя прикреплять файлы к этой странице.