Прикреплённый файл «win.py»
Загрузка 1 #!/usr/bin/python
2 # coding: utf-8
3 # vim: expandtab:ts=4:sw=4
4 '''
5 Написать «оконную систему», состоящую из классов
6
7 * Экран (контейнер окон, позволяет манипулировать окнами)
8 o Список окон, определение окна-получателя события
9 o Глубина окон, изменение глубины окон
10 o Перемещение и изменение размера окон
11 * Окно (позволяет манипулировать своим содержимым)
12
13 win.py: классы
14 '''
15
16 import pygame, sys
17
18 class descriptor:
19 '''Window descritor'''
20 def __init__(self, rect, window, mode=["basic"], **argn):
21 '''Create a window descriptor object with defaut basic mode'''
22 self.rect=rect
23 self.window=window
24 if type(mode) is str:
25 self.mode=[mode]
26 else:
27 self.mode=mode or ["basic"]
28
29 class basic_screen:
30 '''Windows container'''
31 def __init__(self, surface, bg=(0,0,0)):
32 '''Create a screen using given surface'''
33 self.surface = surface
34 self.windows = []
35 self.immed = [] # events to be handled immediately
36 self.hanled = [] # events we handle if no child doesn.t
37 self.bg = bg
38
39 def append(self, rect, mode, creator, *args, **argn):
40 '''Call creator() with *args, **argn
41 to produce a window (of mode type) on rect-sized subsurface
42 and put the window in the top'''
43 wnd = creator(self.surface.subsurface(rect), *args, **argn)
44 self.windows.append(descriptor(rect,wnd,mode))
45 return wnd
46
47 def pop(self, index=-1):
48 '''Unregister corresponded window and return it'''
49 if self.windows:
50 return self.windows.pop(index)
51 else:
52 return None
53
54 def clear(self):
55 '''Draw initial screen's surface without all windows'''
56 if self.bg:
57 self.surface.fill(self.bg)
58
59 def redraw(self):
60 '''Redraw all the contents'''
61 self.clear()
62 for wnd in self.windows:
63 wnd.window.redraw()
64
65 def up(self, index):
66 '''Put indexed window deeper'''
67 if len(self.windows) > 1 and index < len(self.windows)-1:
68 index+=1
69 self.windows[index-1],self.windows[index]= \
70 self.windows[index], self.windows[index-1]
71 return index
72
73 def down(self, index):
74 '''Pull indexed window upper'''
75 if len(self.windows) > 1 and index > 0:
76 self.windows[index-1],self.windows[index]= \
77 self.windows[index] ,self.windows[index-1]
78 index-=1
79 return index
80
81 def top(self, index):
82 '''Bring indexed window to the top'''
83 if index < len(self.windows):
84 w=self.windows.pop(index)
85 self.windows.append(w)
86
87 def locate(self, pos):
88 '''Locate a window than owns visible pos coordinate.
89 If not found return -1'''
90 for i in xrange(len(self.windows)-1, -1, -1):
91 if self.windows[i].rect.collidepoint(pos):
92 return i
93 return -1
94
95 def handler(self, event, pos):
96 '''Handle an event that not correspond any window'''
97 return False
98
99 def proceed(self, event, pos):
100 '''Check if the event is to be handled by certain window
101 and let the window do it. If no appropriete windows found
102 or window nas no idea how to handle an event, handle it manually.
103 Return false if no event handler is provided.'''
104 ret=False
105 if event in self.immed:
106 ret=self.handler(event, pos)
107 if not ret:
108 index=self.locate(pos)
109 if index>=0:
110 wpos=(pos[0]-self.windows[index].rect.left,pos[1]-self.windows[index].rect.top)
111 ret=self.windows[index].window.proceed(event,wpos)
112 return ret or self.handler(event, pos)
113
114 def renew(self,surface):
115 '''Stck window to a new surface'''
116 self.surface = surface
117 for wnd in self.windows:
118 wnd.window.renew(surface.subsurface(wnd.rect))
119
120 class simple_screen(basic_screen):
121 '''Screen with simple window management'''
122 def __init__(self, *argv, **argn):
123 '''Additional parameters:
124 titlebg: title background
125 titlefg: title foreground
126 borderwidth: width of border line
127 bordercolor: base color of border (3D effect applied)
128 '''
129 self.titlebg=argn.get('titlebg',(0,32,64))
130 self.titlefg=argn.get('titlefg',(255,248,128))
131 self.borderwidth=argn.get('borderwidth',2)
132 self.bordercolor=argn.get('bordercolor',(128,128,128))
133 self.titlesize=14
134 basic_screen.__init__(self, *argv, **argn)
135 self.immed.extend([pygame.MOUSEMOTION, pygame.MOUSEBUTTONDOWN])
136 self.focus=-1
137 self.min_w,self.min_h=2*self.borderwidth,2*self.borderwidth
138
139 def handler(self, event, pos):
140 '''
141 pygame.MOUSEMOTION with button1 down -- move focused window
142 pygame.MOUSEBUTTONDOWN with button1 -- focus a window
143 with buttion4/5 -- raise/lower a window
144 '''
145 ret=False
146 if event.type == pygame.MOUSEMOTION:
147 if self.focus >= 0 and event.buttons[0]:
148 nrect = self.windows[self.focus].rect.move(event.rel)
149 if self.surface.get_rect().contains(nrect):
150 self.windows[self.focus].rect.move_ip(event.rel)
151 self.windows[self.focus].window.renew(self.surface.subsurface(self.windows[self.focus].rect))
152 ret=True
153 elif self.focus >= 0 and event.buttons[2]:
154 nrect = self.windows[self.focus].rect.inflate(event.rel)
155 if self.surface.get_rect().contains(nrect) and nrect.w>self.min_w and nrect.h>self.min_h:
156 #print >> sys.stderr, nrect, self.min_w, self.min_h
157 self.windows[self.focus].rect.inflate_ip(event.rel)
158 self.windows[self.focus].window.renew(self.surface.subsurface(self.windows[self.focus].rect))
159 ret=True
160 elif event.type == pygame.MOUSEBUTTONDOWN:
161 index = self.locate(pos)
162 if event.button == 1:
163 if index >=0 and index != self.focus:
164 self.focus=index
165 ret=True
166 elif event.button == 4:
167 self.focus=self.up(index)
168 ret=True
169 elif event.button == 5:
170 if index>0 and "top" not in self.windows[index].mode:
171 self.focus=self.down(index)
172 ret=True
173 return ret
174
175 def highlight_window(self, index):
176 '''Draw 4 black-white circles to merk a window'''
177 for center in [ self.windows[index].rect.topleft,
178 self.windows[index].rect.bottomleft,
179 self.windows[index].rect.topright,
180 self.windows[index].rect.bottomright ]:
181 pygame.draw.circle(self.surface, (0,0,0), center, 4)
182 pygame.draw.circle(self.surface, (255,255,255), center, 3)
183
184 def pop(self, index=-1):
185 w=basic_screen.pop(self,index)
186 if w:
187 # TODO not to lose focus if non-focused window is deleted
188 self.focus=-1
189 return w
190
191 def redraw(self):
192 '''Redraw all windows then highlight focused window, if any'''
193 basic_screen.redraw(self)
194 if self.focus >=0:
195 self.highlight_window(self.focus)
196
197 class basic_window:
198 '''Basic type window'''
199 min_w, min_h = 10, 10
200 def __init__(self, surface, bg=(0,0,0)):
201 '''Create a window based on given surface
202 if bg is None, make transparent window'''
203 self.surface = surface
204 self.bg = bg
205
206 def renew(self,surface):
207 '''Stck window to a new surface'''
208 self.surface = surface
209
210 def redraw(self):
211 if self.bg:
212 self.surface.fill(self.bg)
213
214 def proceed(self, event, pos):
215 return False
216
217 def drawable(self):
218 return self.surface
219
220 class text_window(basic_window):
221 '''Window with text inside'''
222 def __init__(self, surface, bg=(0,0,0), fg=(200,200,200), text='', font="dejavusans", size=14):
223 basic_window.__init__(self, surface, bg)
224 self.fg=fg
225 self.text=text
226 if type(font) is pygame.font.Font:
227 self.font = font
228 else:
229 if not pygame.font.get_init:
230 pygame.font.init()
231 self.font=pygame.font.SysFont(font, size)
232 # TODO calculate this dynamically!
233 self.min_w,self.min_h=self.__fsize()
234
235 def __fsize(self):
236 r,n=self.font.size(self.text),(1,self.font.get_height())
237 return (max(r[0],n[0]),max(r[1],n[1]))
238
239 def redraw(self):
240 tx=self.font.render(self.text,True,self.fg)
241 self.min_w,self.min_h=self.__fsize()
242 basic_window.redraw(self)
243 self.surface.blit(tx,(0,0))
244
245 class screen_window(basic_screen):
246 '''Window with title and frame, screen internal'''
247 def __init__(self, surface, screen, title):
248 '''Use parent simple_creen defaults for title and frame'''
249 basic_screen.__init__(self, surface, screen.bg)
250 self.bordercolor, self.borderwidth = screen.bordercolor, screen.borderwidth
251 self.title = title
252 self.parent = screen
253 trect=self.__trect()
254 self.append(trect, "text", text_window, text=title,
255 bg=screen.titlebg, fg=screen.titlefg, size=screen.titlesize)
256 drect=self.__drect()
257 self.append(drect, "basic", basic_window, bg=screen.bg)
258 self.min_w=self.windows[0].window.min_w+2*screen.borderwidth
259 self.min_h=self.windows[0].window.min_h+self.windows[1].window.min_h+3*screen.borderwidth
260
261 def __trect(self, surface=None):
262 surf = surface or self.surface
263 return pygame.Rect(self.parent.borderwidth, \
264 self.parent.borderwidth, \
265 surf.get_width()-2*self.parent.borderwidth, \
266 self.parent.titlesize+2*self.parent.borderwidth)
267
268 def __drect(self, surface=None):
269 surf = surface or self.surface
270 return pygame.Rect(self.parent.borderwidth, \
271 self.__trect(surface).height+2*self.parent.borderwidth, \
272 self.__trect(surface).width, \
273 surf.get_height()-self.__trect(surface).height-3*self.parent.borderwidth)
274
275 def redraw(self):
276 basic_screen.redraw(self)
277 rect=self.surface.get_rect()
278 x,y,w,h=rect.topleft+rect.size
279 line=((x,y), (x+w-self.borderwidth,y), (x+w-self.borderwidth,y+h-self.borderwidth), (x,y+h-self.borderwidth))
280 pygame.draw.lines(self.surface, self.bordercolor, True, line, self.borderwidth)
281 middle=self.windows[0].rect.height+self.borderwidth
282 pygame.draw.line(self.surface, self.bordercolor, (self.borderwidth,middle), (rect.width-self.borderwidth,middle), self.borderwidth)
283
284 def renew(self,surface):
285 '''Stck window to a new surface'''
286 # TODO cannot deny renew if sizes do not fit :(
287 self.windows[0].rect=self.__trect(surface)
288 self.windows[1].rect=self.__drect(surface)
289 basic_screen.renew(self,surface)
290
291 def drawable(self):
292 return self.windows[1].window.surface
293
294 class edit_window(text_window):
295 '''Simple text input'''
296 def __init__(self, surface, bg=(0,0,0), fg=(200,200,200), text='', font="dejavusans", size=14):
297 text_window.__init__(self, surface, bg, fg, text, font, size)
298 self.cur=len(self.text)
299 self.type="input string"
300
301 def handler(self, event, pos):
302 if event.type == pygame.KEYDOWN:
303 if event.unicode and event.unicode in u'\n\r':
304 pygame.event.post(pygame.event.Event(pygame,USEREVENT, code=[self.type,self.text]))
305 elif event.key == 8:
306 self.text=self.text[:self.cur-1]+self.text[self.cur:]
307 self.cur -=1
308 elif event.key == 276:
309 self.cur = max(0, self.cur - 1)
310 elif event.key == 275:
311 self.cur = min(len(self.text), self.cur + 1)
312 elif event.unicode and event.key >= 32 and event.key not in [ 127 ]:
313 self.text = self.text[:self.cur] + event.unicode + self.text[self.cur:]
314 self.cur+=1
315 else:
316 return False
317 print >> sys.stderr, event
318 return True
319
320 def proceed(self, event, pos):
321 if event.type == pygame.KEYDOWN:
322 return self.handler(event, pos)
323 else: return False
324
325 def redraw(self):
326 text_window.redraw(self)
327 tx=self.font.size(self.text[:self.cur])
328 pygame.draw.line(self.surface,(255,255,0),(tx[0]+1,1), (tx[0]+1,tx[1]+1))
Прикреплённые файлы
Для ссылки на прикреплённый файл в тексте страницы напишите attachment:имяфайла, как показано ниже в списке файлов. Не используйте URL из ссылки «[получить]», так как он чисто внутренний и может измениться.- [получить | показать] (2011-09-26 11:35:37, 12.7 KB) [[attachment:win.py]]
- [получить | показать] (2011-09-26 11:35:37, 2.3 KB) [[attachment:winrun.py]]
Вам нельзя прикреплять файлы к этой странице.