Прикреплённый файл «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.05
  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=""
  49     DefaultText=""
  50     CheckType=str
  51     RetryIncorrect=True
  52     TextLength=0
  53     FontID=None
  54     Font=None
  55     FontSize=24
  56     PromptGap=None
  57     Size=None
  58     BackingStore=None
  59     RepeatStore=None
  60     RepeatDefault=(500,100)
  61 
  62     def __update__(self, *pargs, **nargs):
  63         '''Update box properties.
  64         Positional parameters: [Prompt, [DefaultText]].
  65         Named parameters: all class data fields.
  66         
  67         - Size supercedes FontSize, default FontSize is 24
  68         - setting DefaultText also sets CheckType (so use 0., not "0" for float input)
  69         '''
  70         if len(pargs)>0:
  71             self.Prompt=pargs[0]
  72         if len(pargs)>1:
  73             self.DefaultText=unicode(pargs[1])
  74             self.CheckType=type(pargs[1])
  75         for prop in nargs:
  76             if hasattr(self,prop):
  77                 setattr(self,prop,nargs[prop])
  78         if not self.FontID:
  79             self.FontID=pygame.font.match_font("sans")
  80         if self.PromptGap is None and self.Prompt:
  81             self.PromptGap=" "
  82         if "CheckType" not in nargs and "DefaultText" in nargs:
  83             self.CheckType=type(nargs["DefaultText"])
  84         if "Size" in nargs:
  85             self.FontSize=self.Size[1]-2*self.BorderWidth
  86             self.Font=pygame.font.Font(self.FontID, self.FontSize)
  87         elif not self.Size:
  88             self.Font=pygame.font.Font(self.FontID, self.FontSize)
  89             self.Size=self.Font.size(self.Prompt+self.PromptGap+"W"*max(self.TextLength,len(self.DefaultText)+1,2))
  90             self.Size=self.Size[0]+2*self.BorderWidth,self.Size[1]+2*self.BorderWidth
  91         self.Paper=pygame.Surface(self.Size)
  92         # TODO background image/transparency for Paper
  93         self.Paper.fill(self.PaperColor)
  94         pr=self.Font.render(self.Prompt, True, self.PromptColor)
  95         self.Paper.blit(pr, (self.BorderWidth,self.BorderWidth+self.FontSize-self.Font.get_height()))
  96         self.Text=unicode(self.DefaultText)
  97         self.Cursor=len(self.Text)
  98 
  99     def __init__(self, *pargs, **nargs):
 100         '''Create a text input entity. Call __update__() next.'''
 101         self.__update__(*pargs, **nargs)
 102 
 103     def __sawtoothed__(self, block, side, mult=3):
 104         '''Create a sawtoothed mark for left (False) or right (True) side'''
 105         w,h=block.get_size()
 106         nw=mult*self.BorderWidth
 107         n=(h/nw)|1
 108         x,d=side and (w-1,-nw) or (0,nw)
 109         return [(x+d*(i%2),h*i/n) for i in xrange(n)]
 110 
 111     def value(self):
 112         '''Check if input is correct and return it, return None if it is not'''
 113         try:
 114             return self.CheckType(self.Text)
 115         except:
 116             return None
 117 
 118     def render(self):
 119         '''Return paper surface with current prompt and text printed on'''
 120         ret=self.Paper.copy()
 121         wl=self.Font.size(self.Prompt+self.PromptGap)[0]
 122         ib=ret.subsurface((wl,0,ret.get_width()-wl,ret.get_height()))
 123         ia=ret.subsurface((wl+self.BorderWidth,self.BorderWidth,ret.get_width()-wl-2*self.BorderWidth,ret.get_height()-2*self.BorderWidth))
 124         pr=self.Font.render(self.Text, True, self.TextColor)
 125         w=self.Font.size(self.Text[:self.Cursor])[0]
 126         while self.Margin and w-self.Font.size(self.Text[:self.Margin])[0]<self.CursorWidth:
 127             self.Margin-=1
 128         while w-self.Font.size(self.Text[:self.Margin])[0]>ia.get_width()-self.CursorWidth:
 129             self.Margin+=1
 130         Margin=-self.Font.size(self.Text[:self.Margin])[0]
 131         ia.blit(pr,(Margin,self.FontSize-self.Font.get_height()))
 132         pygame.draw.line(ia, self.CursorColor, (w+Margin,2), (w+Margin,ia.get_height()-2),self.CursorWidth)
 133         if Margin<0:
 134             pygame.draw.polygon(ib, self.OverColor, self.__sawtoothed__(ib, False))
 135         if Margin+pr.get_width()>ia.get_width()-self.CursorWidth:
 136             pygame.draw.polygon(ib, self.OverColor, self.__sawtoothed__(ib, True))
 137         return ret
 138 
 139     def draw(self,scr,pos):
 140         '''Draw input box on surface scr at position pos
 141         backuping an underlying part of surface'''
 142         self.BackingStore=(self.Paper.copy(),scr,pos)
 143         self.BackingStore[0].blit(self.BackingStore[1],(0,0),(self.BackingStore[2],self.Size))
 144         self.BackingStore[1].blit(self.render(),self.BackingStore[2])
 145         self.Status|=SHOWN
 146 
 147     def undraw(self):
 148         '''Remove the box from the surface it was drawn
 149         restoring underlying part of surface'''
 150         if self.BackingStore:
 151             self.BackingStore[1].blit(self.BackingStore[0],self.BackingStore[2])
 152         self.Status&=~SHOWN
 153 
 154     def activate(self, *pargs, **nargs):
 155         '''Enable input from the box.
 156         If either pargs or nargs is given, call __update__().
 157         Return False if no activation was needed, True otherwise.
 158 
 159         Calling __update__() means resetting every field,
 160         so use `inputbox.activate("<any prompt>")' to replace
 161         last entered value with the default one.
 162         '''
 163         if self.Status&ACTIVE and not pargs and not nargs:
 164             return False
 165         if pargs or nargs:
 166             self.__update__(*pargs, **nargs)
 167         self.Cursor=len(self.Text)
 168         self.Margin=0
 169         self.Status=ACTIVE|FIRST
 170         self.RepeatStore=pygame.key.get_repeat()
 171         pygame.key.set_repeat(*self.RepeatDefault)
 172         return True
 173 
 174     def deactivate(self):
 175         '''Disable input from the box'''
 176         if self.Status:
 177             self.Status=0
 178             pygame.key.set_repeat(*self.RepeatStore)
 179 
 180     def is_active(self): return self.Status&ACTIVE
 181     def is_done(self): return self.Status&DONE
 182     def is_failed(self): return self.Status&FAILED
 183     def is_cancelled(self): return self.Status&CANCEL
 184     def is_shown(self): return self.Status&SHOWN
 185 
 186     def is_success(self):
 187         return self.is_done() and not (self.is_failed() or self.is_cancelled())
 188 
 189     def edit(self,ev):
 190         '''Proceed event for editing input box.
 191         Supported keys:
 192             <any unicode symbol>:   input character
 193             <backspace>:            delete character under the cursor
 194             <esc>:                  restore default value
 195             <esc><esc>:             force unsuccsessful input'''
 196         if ev.type is pygame.KEYDOWN:
 197             if ev.key == pygame.K_BACKSPACE:
 198                 if self.Cursor>0:
 199                     self.Text=self.Text[:self.Cursor-1]+self.Text[self.Cursor:]
 200                     self.Cursor-=1
 201             elif ev.key == pygame.K_DELETE:
 202                 if self.Cursor<len(self.Text):
 203                     self.Text=self.Text[:self.Cursor]+self.Text[self.Cursor+1:]
 204             elif ev.unicode >= u' ':
 205                 if self.Status&FIRST:
 206                     self.Text=ev.unicode
 207                     self.Cursor=1
 208                 else:
 209                     self.Text=self.Text[:self.Cursor]+ev.unicode+self.Text[self.Cursor:]
 210                     self.Cursor+=1
 211             elif ev.key == pygame.K_ESCAPE:
 212                 if self.Text==self.DefaultText:
 213                      self.Status|=CANCEL|DONE
 214                 self.Text=self.DefaultText
 215                 self.Margin=0
 216             elif ev.key == pygame.K_RETURN:
 217                 if self.value() is None:
 218                     if self.RetryIncorrect:
 219                         # TODO signal an error
 220                         self.Text=self.DefaultText
 221                         self.Margin=0
 222                     else:
 223                         self.Status|=DONE|FAILED
 224                 else:
 225                     self.Status|=DONE
 226             elif ev.key == pygame.K_HOME:
 227                 self.Cursor=0
 228             elif ev.key == pygame.K_END:
 229                 self.Cursor=len(self.Text)
 230             elif ev.key == pygame.K_RIGHT:
 231                 self.Cursor=min(self.Cursor+1,len(self.Text))
 232             elif ev.key == pygame.K_LEFT:
 233                 self.Cursor=max(self.Cursor-1,0)
 234             self.Status&=~FIRST
 235 
 236 def __main():
 237     import random
 238     _=random.randint
 239     pygame.init()
 240     Size=(760,180)
 241     Scr=pygame.display.set_mode(Size)
 242     Scr.fill(pygame.Color("Black"))
 243     #inp=Input("", "Default text", FontSize=36)
 244     #inp=Input("Float input:", "123", FontSize=36, CheckType=float)
 245     r=20
 246     for i in xrange(100):
 247         pos=_(r,Size[0]-r),_(r,Size[1]-r)
 248         col=_(10,255),_(10,255),_(10,255)
 249         pygame.draw.circle(Scr,col,pos,r)
 250     x,y=Size[0]/12,Size[1]/5
 251     inp=Input("Input",Size=(Size[0]-2*x,Size[1]-2*y))
 252     cont,verbose=True,False
 253     defaults,defcnt=(("String",""),("Int",0),("Float",0.)),0
 254     while cont:
 255         for ev in pygame.event.get():
 256             if verbose:
 257                 print ev
 258             if ev.type is pygame.QUIT:
 259                 cont=False
 260             if ev.type is pygame.KEYDOWN and inp.is_active():
 261                 inp.edit(ev)
 262             elif ev.type is pygame.KEYDOWN:
 263                 if ev.key in (pygame.K_KP_ENTER, pygame.K_RETURN, 13):
 264                     if not inp.is_active():
 265                         inp.activate(*defaults[defcnt])
 266                         defcnt=(defcnt+1)%len(defaults)
 267                 elif ev.key == pygame.K_F1:
 268                     verbose=True
 269                 elif ev.key is pygame.K_ESCAPE:
 270                     if not inp.is_active():
 271                         cont=False
 272 
 273         if inp.is_done():
 274             if inp.is_failed():
 275                 print "Data incorrect"
 276             elif inp.is_cancelled():
 277                 print "Input is cancelled"
 278             else:
 279                 print "Result: '{0}'".format(inp.value())
 280             inp.deactivate()
 281 
 282         if inp.is_active(): inp.draw(Scr,(x,y))
 283         pygame.display.flip()
 284         if inp.is_active(): inp.undraw()
 285     quit()
 286 
 287 if __name__ == "__main__":
 288     __main()

Прикреплённые файлы

Для ссылки на прикреплённый файл в тексте страницы напишите attachment:имяфайла, как показано ниже в списке файлов. Не используйте URL из ссылки «[получить]», так как он чисто внутренний и может измениться.

Вам нельзя прикреплять файлы к этой странице.