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