Commit before breaking everything
[matches/honours.git] / research / transmission_spectroscopy / simulator / pgu-0.18 / build / scripts-3.2 / leveledit
1 #!C:\Python32\python.exe
2 """<title>a simple level editor for pygame</title>
3 <pre>
4 usage: leveledit level.tga [tiles.tga] [codes.tga] [tile_w] [tile_h]
5 windows: python leveledit level.tga [tiles.tga] [codes.tga] [tile_w] [tile_h]
6
7 options:
8   -h, --help            show this help message and exit
9   -tTILES, --tiles=TILES
10                         filename of the tiles image
11   -cCODES, --codes=CODES
12                         file name of the codes image
13   --tw=TILE_W           tile width
14   --th=TILE_H           tile height
15   --vw=VIEW_W           view width
16   --vh=VIEW_H           view height
17   --sw=SCREEN_W         screen width
18   --sh=SCREEN_H         screen height
19   --c=CLASS             class (e.g. pgu.tilevid.Tilevid)
20   --tile                use pgu.tilevid.Tilevid
21   --iso                 use pgu.isovid.Isovid
22   --hex                 use pgu.hexvid.Hexvid
23   -a, --app             set application level defaults
24
25 example:
26 leveledit level.tga tiles.tga codes.tga 16 16
27
28 note:
29 the editor can only edit tga files.  the output files will
30 have the "tile" layer in the red channel, the "bkgr" layer
31 in the green channel, and the "code" layer in the blue channel.
32
33 you may edit default options in leveledit.ini
34
35 interface:
36 - menus for common commands
37 - toolbox
38 - tile edit area
39     left click to use current tool
40     right click to select a tile
41     middle drag to move around the level
42 - tile select area
43     click to select a tile
44 - code select area
45     click to select a code
46
47 keys:
48 l - load
49 s - save
50 p - preview
51
52 a - select all
53 z - undo
54 c - copy selection to clipboard
55 v - paste clipboard at selection origin
56 delete - delete selection
57 f - fill selection
58
59 t - switch tile & bkgr layers
60
61 arrows - change tile
62 shift+arrows - scroll screen by 1/8 screen size jumps
63 ctrl+arrows - scroll screen by full screen size jumps
64 return - toggle fullscreen
65 </pre>
66 """
67
68 import os,sys    
69 from optparse import OptionParser
70 from ConfigParser import ConfigParser
71 import pygame
72 from pygame.locals import *
73
74 # the following line is not needed if pgu is installed
75 import sys; sys.path.insert(0, "..")
76
77 from pgu import gui, html, tilevid, isovid, hexvid
78
79
80
81 #whatever...
82 ini_fname = "leveledit.ini"
83 ini = ConfigParser()
84 cfg = {}
85
86 class _app(gui.Container):
87     def __init__(self):
88         gui.Container.__init__(self)
89         #self.cls = "desktop"
90         #self.background = gui.Box(self.style.background)
91
92         self.screen_w = cfg['screen_w']
93         self.screen_h = cfg['screen_h']
94         self.screen = pygame.display.set_mode((self.screen_w,
95             self.screen_h), SWSURFACE)
96
97         self.fname = cfg['fname']
98         
99         k = cfg['class']
100         parts = k.split(".")
101         n = ".".join(parts[:-1])
102         m = __import__(n,globals(),locals(),parts[-1])
103         c = getattr(m,parts[-1])
104         self.level = c()
105
106         #self.level = pygame.image.load(self.level_fname)
107         #self.level = tilevid.Tilevid()
108         #g = self.level = isovid.Isovid()
109         
110     
111         if self.fname != None:
112             self.level.tga_load_level(self.fname,1)
113         else:
114             self.level.resize((cfg['width'],cfg['height']),1)
115         #self.level_w, self.level_h = (self.level.get_width(), self.level.get_height())
116         self.level_w, self.level_h = len(self.level.tlayer[0]),len(self.level.tlayer)
117
118         self.tiles_last_ctime = None
119         self.codes_last_ctime = None
120
121         self.load_tiles_and_codes()
122         
123
124
125
126         
127         
128         self.tile = 0
129         self.code = 0
130         
131         self.mode = 'tile'
132         self.clipboard = None
133         self.history = []
134         #self.modrect = pygame.Rect(0xffff,0xffff,-0xffff,-0xffff)
135         
136         self.changes = []
137         self.dirty = 0
138         
139
140     def load_tiles_and_codes(self):
141         #
142         #
143
144         self.tile_w, self.tile_h = cfg['tile_w'], cfg['tile_h']
145
146         self.tiles_fname = cfg['tiles']
147         if os.path.isfile(self.tiles_fname):
148             # we check to see if the ctime is the same.
149
150             newctime = os.stat(self.tiles_fname)[9]
151             if newctime <= self.tiles_last_ctime:
152                 #nothing to do, so we return.
153                 return
154
155             self.tiles_last_ctime = newctime
156
157             self.tiles = pygame.image.load(self.tiles_fname)
158         else:
159             self.tiles = hex_image(self)
160         self.tiles_w, self.tiles_h = (self.tiles.get_width(),
161             self.tiles.get_height())
162         self.level.tga_load_tiles(self.tiles,(self.tile_w,self.tile_h))
163
164         self.codes_fname = cfg['codes']
165         if os.path.isfile(self.codes_fname):
166             newctime = os.stat(self.codes_fname)[9]
167             if newctime <= self.codes_last_ctime:
168                 #nothing to do, so we return.
169                 return
170             self.codes_last_ctime = newctime
171
172             self.codes = pygame.image.load(self.codes_fname)
173         else:
174             self.codes = hex_image(self)
175                         
176         self.codes_w, self.codes_h = (self.codes.get_width(),
177             self.codes.get_height())
178
179         
180         tmp = self.level.tiles
181         self.level.tiles = [None for i in xrange(0,256)]
182         self.level.tga_load_tiles(self.codes,(self.tile_w,self.tile_h))
183         self.level.codes = self.level.tiles
184         self.level.tiles = tmp
185
186
187
188
189
190
191     def mod(self,rect):
192         self.dirty = 1
193         self.changes.append((pygame.Rect(rect),self.copy(rect)))
194     
195
196     def view_init(self,dw,dh):        
197         
198         self.view_w = dw #/ self.tile_w
199         self.view_h = dh #/ self.tile_h
200         
201         if 'view_w' in cfg and cfg['view_w'] != 0:
202             self.view_w = min(self.view_w, cfg['view_w'])
203         if 'view_h' in cfg and cfg['view_h'] != 0:
204             self.view_h = min(self.view_h, cfg['view_h'])
205         
206         #self.view_w = min(self.level.size[0],self.view_w)
207         #self.view_h = min(self.level.size[1],self.view_h)
208         
209         #print self.view_w,self.view_h
210         
211         #self.view = self.level.subsurface((0,0,self.view_w,self.view_h))
212         self.select = Rect(0,0,self.level.size[0],self.level.size[1]) #self.view_w,self.view_h)
213         
214     def fill(self,rect,v):
215         lvl = self.level
216         w,h = lvl.size
217         
218         for layer,n in [ (lvl.tlayer,0), (lvl.blayer,1), (lvl.clayer,2) ]:
219             for y in range(0,rect.h):
220                 for x in range(0,rect.w):
221                     tx,ty = x+rect.x,y+rect.y
222                     if tx >= 0 and tx < w and ty >= 0 and ty < h: layer[ty][tx] = v[n]
223         
224     def copy(self,rect):
225         data = [[[None for x in range(0,rect.w)] for y in range(0,rect.h)] for l in range(0,4)] 
226
227         lvl = self.level
228         w,h = lvl.size
229         
230         for layer,n in [ (lvl.tlayer,0), (lvl.blayer,1), (lvl.clayer,2) ]:
231             for y in range(0,rect.h):
232                 for x in range(0,rect.w):
233                     tx,ty = x+rect.x,y+rect.y
234                     if tx >= 0 and tx < w and ty >= 0 and ty < h: data[n][y][x] = layer[ty][tx]
235         return data
236                 
237     def paste(self,rect,data):
238         lvl = self.level
239         w,h = lvl.size
240         
241         for layer,n in [ (lvl.tlayer,0), (lvl.blayer,1), (lvl.clayer,2) ]:
242             for y in range(0,rect.h):
243                 for x in range(0,rect.w):
244                     tx,ty = x+rect.x,y+rect.y
245                     v = data[n][y][x]
246                     if v != None and tx >= 0 and tx < w and ty >= 0 and ty < h: layer[ty][tx] = v
247         
248         
249     def archive(self):
250         if not len(self.changes): return
251         
252         self.dirty = 1
253         h = self.history
254         if len(h) >= 32:
255             del h[0]
256         #c = pygame.Surface((self.view_w,self.view_h),SWSURFACE,self.view)
257         #c.fill((0,0,0,0))
258         #c.blit(self.view,(0,0))
259         
260         lvl = self.level
261         #ox,oy = lvl.screen_to_tile((0,0))
262         #bx,by = lvl.screen_to_tile((self.vdraw.rect.w,self.vdraw.rect.h))
263         
264         #rect = pygame.Rect(ox,oy,bx-ox,by-oy)
265         #print self.modrect
266         
267         h.append(self.changes)
268         self.changes = []
269         
270     def undo(self):
271         if len(self.changes): self.archive()
272             
273         if len(self.history) == 0: return
274         
275         self.dirty = 1
276         changes = self.history.pop()
277         
278         changes.reverse()
279         for rect,data in changes:
280             self.paste(rect,data)
281             
282         self.vdraw.repaint()
283         self.tpicker.repaint() #huh?
284         
285         self.changes = []
286         return
287         
288         self.level.fill((0,0,0,0),(off[0],off[1],self.view_w,self.view_h))
289         self.level.blit(c,off)
290         self.vdraw.repaint()
291         self.tpicker.repaint()
292         
293     def __setattr__(self,k,v):
294         self.__dict__[k] = v
295         
296         if k == 'view':
297             if hasattr(self,'vdraw'): self.vdraw.repaint()
298         
299         if k == 'tile':
300             if hasattr(self,'tpicker'): self.tpicker.repaint()
301                 
302         if k == 'code':
303             if hasattr(self,'cpicker'): self.cpicker.repaint()
304         
305             
306     def event(self,e):
307         if e.type is KEYDOWN:
308             for key,cmd,value in keys:
309                 if e.key == key:
310                     cmd(value)
311                     return
312         return gui.Container.event(self,e)
313     
314
315 def hex_image(self):
316     if not hasattr(self,'tiles_w'): self.tiles_w = 256
317     if not hasattr(self,'tiles_h'): self.tiles_h = 256
318     rimg = pygame.Surface((self.tiles_w,self.tiles_h)).convert_alpha()
319     rimg.fill((0,0,0,0))
320     w,h = self.tiles_w / self.tile_w, self.tiles_h / self.tile_h
321     n = 0
322     fnt = pygame.font.SysFont("helvetica",self.tile_h-1)
323     for y in range(0,h):
324         for x in range(0,w):
325             n = x+y*w
326             if n != 0:
327                 xx,yy = x*self.tile_w,y*self.tile_h
328                 img = fnt.render("%02X"%n,0,(0,0,0))
329                 img = pygame.transform.scale(img,(self.tile_w-1,self.tile_h-1))
330                 rimg.blit(img,(xx+1,yy+1))
331                 img = fnt.render("%02X"%n,0,(255,255,255))
332                 img = pygame.transform.scale(img,(self.tile_w-1,self.tile_h-1))
333                 rimg.blit(img,(xx,yy))
334     return rimg
335
336
337 class tpicker(gui.Widget):
338     def __init__(self):
339         gui.Widget.__init__(self)
340         self.style.width = app.tiles_w
341         self.style.height = app.tiles_h
342         
343     def paint(self,s):
344         s.fill((128,128,128))
345         s.blit(app.tiles,(0,0))
346         w = app.tiles_w/app.tile_w
347         x,y = app.tile%w,app.tile/w
348         off = x*app.tile_w,y*app.tile_h
349         pygame.draw.rect(s,(255,255,255),(off[0],off[1],app.tile_w,app.tile_h),2)
350         
351     def event(self,e):
352         if (e.type is MOUSEBUTTONDOWN and e.button == 1) or (e.type is MOUSEMOTION and e.buttons[0] == 1 and self.container.myfocus == self):
353             w = app.tiles_w/app.tile_w
354             x,y = e.pos[0]/app.tile_w,e.pos[1]/app.tile_h
355             n = x+y*w
356             self.set(n)
357             if app.mode not in ('tile','bkgr'):
358                 app.tools['tile'].click()
359     
360     def set(self,n):
361         if n < 0 or n >= len(app.level.tiles) or app.level.tiles[n] == None: return
362         app.tile = n
363
364
365 class cpicker(gui.Widget):
366     def __init__(self):
367         gui.Widget.__init__(self)
368         self.style.width = app.codes_w
369         self.style.height = app.codes_h
370         
371     def paint(self,s):
372         s.fill((128,128,128))
373         s.blit(app.codes,(0,0))
374         w = app.codes_w/app.tile_w
375         x,y = app.code%w,app.code/w
376         off = x*app.tile_w,y*app.tile_h
377         pygame.draw.rect(s,(255,255,255),(off[0],off[1],app.tile_w,app.tile_h),2)
378         
379     def event(self,e):
380         if (e.type is MOUSEBUTTONDOWN and e.button == 1) or (e.type is MOUSEMOTION and e.buttons[0] == 1 and self.container.myfocus == self):
381             w = app.codes_w/app.tile_w
382             x,y = e.pos[0]/app.tile_w,e.pos[1]/app.tile_h
383             n = x+y*w
384             self.set(n)
385             app.tools['code'].click()
386     
387     def set(self,n):
388         if n < 0 or n >= len(app.level.codes) or app.level.codes[n] == None: return
389         app.code = n
390
391
392
393 class vwrap(gui.Table):
394     def __init__(self,**params):
395         gui.Table.__init__(self,**params)
396         self.style.width = app.view_w #* app.tile_w
397         self.style.height = app.view_h #* app.tile_h
398         w,h = self.rect.w,self.rect.h = self.style.width,self.style.height
399         
400         sw = 16
401         
402         self.vdraw = e = vdraw(width=w-sw,height=h-sw)
403         self.add(e,0,0)
404         
405         rect = pygame.Rect(0,0,app.level.size[0],app.level.size[1])
406         tcorners = [rect.topleft,rect.topright,rect.bottomright,rect.bottomleft] 
407         corners = [app.level.tile_to_view(tcorners[n]) for n in range(0,4)]
408         
409         minx,miny,maxx,maxy = 0xffff,0xffff,-0xffff,-0xffff
410         for x,y in corners:
411             minx,miny,maxx,maxy = min(minx,x),min(miny,y),max(maxx,x),max(maxy,y)
412
413         minx -= w/2
414         maxx -= w/2
415         miny -= h/2
416         maxy -= h/2
417         
418         self.vs = e = gui.VSlider(0,miny,maxy,sw*4,width=sw,height=h-sw)
419         self.add(e,1,0)
420         e.connect(gui.CHANGE,self.move_y,e)
421         
422         self.hs = e = gui.HSlider(0,minx,maxx,sw*4,width=w-sw,height=sw)
423         self.add(e,0,1)
424         e.connect(gui.CHANGE,self.move_x,e)
425         
426     def move_x(self,value):
427         v = value.value
428         if app.level.view.x != v:
429             app.level.view.x = v
430             app.vdraw.repaint()
431     
432     def move_y(self,value):
433         v = value.value
434         if app.level.view.y != v:
435             app.level.view.y = v
436             app.vdraw.repaint()
437         
438     def adjust(self):
439         self.vs.value = app.level.view.y
440         self.hs.value = app.level.view.x
441         
442
443 class vdraw(gui.Widget):
444     def repaint(self):
445         self.container.adjust()
446         gui.Widget.repaint(self)
447         
448     def __init__(self,**params):
449         gui.Widget.__init__(self,**params)
450         #self.style.width = app.view_w #* app.tile_w
451         #self.style.height = app.view_h #* app.tile_h
452         self.rect.w,self.rect.h = self.style.width,self.style.height
453         
454         s = pygame.Surface((self.rect.w,self.rect.h))
455         clrs = [(148,148,148),(108,108,108)]
456         inc = 7
457         for y in range(0,self.rect.w/inc):
458             for x in range(0,self.rect.h/inc):
459                 s.fill(clrs[(x+y)%2],(x*inc,y*inc,inc,inc))
460         self.bg = s
461
462         s = pygame.Surface((self.rect.w,self.rect.h)).convert_alpha()
463         s.fill((0,0,0,0))
464         for x in range(0,app.view_w):
465             pygame.draw.line(s,(0,0,0),(self.rect.w*x/app.view_w,0),(self.rect.w*x/app.view_w,self.rect.h))
466         for y in range(0,app.view_h):
467             pygame.draw.line(s,(0,0,0),(0,self.rect.h*y/app.view_h),(self.rect.w,self.rect.h*y/app.view_h))
468         self.grid = s
469         
470         self.pos = 0,0
471
472         
473     def paint(self,s):
474         #print s
475         #print s.get_width(),s.get_height(),s.get_clip()
476         #s.blit(self.bg,(0,0))
477         s.fill((128,128,128))
478
479         #make sure to clamp the bounds
480         if app.level.bounds != None:
481             app.level.view.clamp_ip(app.level.bounds)
482         
483         #draw border        
484         rect = pygame.Rect(0,0,app.level.size[0],app.level.size[1])
485         tcorners = [rect.topleft,rect.topright,rect.bottomright,rect.bottomleft]
486         corners = [app.level.tile_to_screen(tcorners[n]) for n in range(0,4)]
487         pygame.draw.lines(s,(255,255,0),1,corners,2)
488
489         
490         #s.fill((0,0,0))
491         #0/0
492         app.level.paint(s)
493         
494         tmp_tiles = app.level.tiles
495         tmp_tlayer = app.level.tlayer
496         tmp_blayer = app.level.blayer
497         
498         app.level.tiles = app.level.codes
499         app.level.tlayer = app.level.clayer
500         app.level.blayer = None
501         
502         app.level.paint(s)
503         
504         app.level.tiles = tmp_tiles
505         app.level.tlayer = tmp_tlayer
506         app.level.blayer = tmp_blayer
507         
508         rect = pygame.Rect(self.pos[0],self.pos[1],1,1)
509         tcorners = [rect.topleft,rect.topright,rect.bottomright,rect.bottomleft]
510         corners = [app.level.tile_to_screen(tcorners[n]) for n in range(0,4)]
511         pygame.draw.lines(s,(196,196,196),1,corners,2)
512
513         rect = pygame.Rect(app.select.x,app.select.y,app.select.w,app.select.h) 
514         tcorners = [rect.topleft,rect.topright,rect.bottomright,rect.bottomleft]
515         corners = [app.level.tile_to_screen(tcorners[n]) for n in range(0,4)]
516         pygame.draw.lines(s,(255,255,255),1,corners,2)
517
518
519                 
520         
521         #s.blit(self.grid,(0,0))
522         #r = app.select
523         #pygame.draw.rect(s,(255,255,255,128),Rect(r.x*self.rect.w/app.view_w,r.y*self.rect.h/app.view_h,r.w*self.rect.w/app.view_w,r.h*self.rect.h/app.view_h),4)
524         
525     def event(self,e):
526         if e.type is MOUSEMOTION:
527             self.getpos(e)
528         if (e.type is MOUSEBUTTONDOWN and e.button == 3) or (e.type is MOUSEMOTION and e.buttons[2]==1 and self.container.myfocus == self):
529             self.picker_down(e)
530         if e.type is MOUSEBUTTONDOWN and e.button == 1:
531             self.getpos(e)
532             a = '%s_down'%app.mode
533             if hasattr(self,a): getattr(self,a)(e)
534         if e.type is MOUSEMOTION and e.buttons[0] and self.container.myfocus == self:
535             a = '%s_drag'%app.mode
536             if hasattr(self,a): getattr(self,a)(e)
537         if e.type is MOUSEBUTTONUP and e.button == 1:
538             a = '%s_up'%app.mode
539             if hasattr(self,a): getattr(self,a)(e)
540         if e.type is MOUSEBUTTONDOWN and e.button == 2:
541             self.move_down(e)
542         if e.type is MOUSEMOTION and e.buttons[1] and self.container.myfocus == self:
543             self.move_drag(e)
544     
545     #move
546     def move_down(self,e):
547         self.moff = app.level.view.x,app.level.view.y
548         self.m1 = e.pos
549         
550     def move_drag(self,e):
551         m1 = self.m1
552         m2 = e.pos
553         #app.view = app.level.subsurface((x,y,app.view_w,app.view_h))
554         app.level.view.x,app.level.view.y = self.moff[0] + m1[0]-m2[0], self.moff[1]+m1[1]-m2[1]
555         self.repaint()
556             
557     #picker
558     def picker_down(self,e):
559         pos = self.getpos(e)
560         #tx,ty = app.level.screen_to_tile(e.pos)
561         #r,g,b,a = app.view.get_at(pos)
562         if pos == None: return 
563         tx,ty = pos
564         
565         if app.mode == 'tile':
566             app.tile = app.level.tlayer[ty][tx]
567         if app.mode == 'bkgr':
568             app.tile = app.level.blayer[ty][tx]
569         app.code = app.level.clayer[ty][tx]
570         
571     
572     
573     #tile
574     def tile_down(self,e):
575         app.archive()
576         self.tile_drag(e)
577     
578     def tile_drag(self,e):
579         pos = self.getpos(e)
580         #r,g,b,a = app.view.get_at(pos)
581         #r = app.tile
582         #app.view.set_at(pos,(r,g,b))
583         
584         if pos == None: return
585         tx,ty = pos
586         app.mod(pygame.Rect(tx,ty,1,1))
587         app.level.tlayer[ty][tx] = app.tile
588         self.repaint()
589         
590     #bkgr
591     def bkgr_down(self,e):
592         app.archive()
593         self.bkgr_drag(e)
594     
595     def bkgr_drag(self,e):
596         pos = self.getpos(e)
597         #r,g,b,a = app.view.get_at(pos)
598         #g = app.tile
599         #app.view.set_at(pos,(r,g,b))
600         if pos == None: return
601         tx,ty = pos
602         app.mod(pygame.Rect(tx,ty,1,1))
603         app.level.blayer[ty][tx] = app.tile
604         self.repaint()
605         
606         
607     #code
608     def code_down(self,e):
609         app.archive()
610         self.code_drag(e)
611     
612     def code_drag(self,e):
613         pos = self.getpos(e)
614         #r,g,b,a = app.view.get_at(pos)
615         #b = app.code
616         #app.view.set_at(pos,(r,g,b))
617         if pos == None: return
618         tx,ty =  pos
619         app.mod(pygame.Rect(tx,ty,1,1))
620         app.level.clayer[ty][tx] = app.code
621         self.repaint()
622         
623     #eraser
624     def eraser_down(self,e):
625         app.archive()
626         self.eraser_drag(e)
627     
628     def eraser_drag(self,e):
629         pos = self.getpos(e)
630         if pos == None: return
631         tx,ty = pos
632         app.mod(pygame.Rect(tx,ty,1,1))
633         app.level.tlayer[ty][tx] = 0
634         app.level.blayer[ty][tx] = 0
635         app.level.clayer[ty][tx] = 0
636         #app.view.set_at(pos,(0,0,0))
637         self.repaint()
638         
639     def getpos(self,e):
640         tx,ty = app.level.screen_to_tile(e.pos)
641         
642         if tx < 0 or ty < 0 or tx >= app.level.size[0] or ty >= app.level.size[1]: return None
643         
644         if (tx,ty) != self.pos:
645             self.pos = tx,ty
646             self.repaint()
647         return tx,ty
648         
649         x,y = e.pos[0]/app.tile_w,e.pos[1]/app.tile_h
650         x = min(max(0,x),app.view_w-1)
651         y = min(max(0,y),app.view_h-1)
652         return x,y
653     
654     def getpos2(self,e):
655         tx,ty = app.level.screen_to_tile(e.pos)
656         
657         return tx+1,ty+1
658         
659         w = app.tile_w
660         h = app.tile_h
661         x,y = (e.pos[0]+w/2)/app.tile_w,(e.pos[1]+h/2)/app.tile_h
662         x = min(max(0,x),app.view_w)
663         y = min(max(0,y),app.view_h)
664         return x,y
665     
666     #select
667     def select_down(self,e):
668         pos = self.getpos2(e)
669         pos = pos[0]-1,pos[1]-1
670         app.select = Rect(pos[0],pos[1],1,1)
671         self.repaint()
672         
673     def select_drag(self,e):
674         pos = self.getpos2(e)
675         app.select = Rect(app.select.x,app.select.y,pos[0]-app.select.x,pos[1]-app.select.y)
676         app.select.w = max(1,app.select.w)
677         app.select.h = max(1,app.select.h)
678
679         self.repaint()
680         
681
682 def cmd_all(value):
683     app.select = Rect(0,0,app.level.size[0],app.level.size[1])
684     app.vdraw.repaint()
685     
686     #print 'deprecated in v0.5'
687     
688 def cmd_shrink(value):    
689     if app.select.w <= 2 or app.select.h <= 2: return
690     app.select.x += 1
691     app.select.y += 1
692     app.select.w -= 2
693     app.select.h -= 2
694
695 def cmd_undo(value):
696     app.undo()
697     
698 def cmd_redo(value):
699     pass
700     
701 def cmd_copy(value):
702     #next version of pygame?
703     #app.clipboard = app.tile.subsurface(app.select).copy()
704     
705     data = app.copy(app.select)
706     app.clipboard = pygame.Rect(app.select),data
707     return
708     
709     #s = app.view.subsurface(app.select)
710     #app.clipboard = pygame.Surface((app.select.w,app.select.h),SWSURFACE,s)
711     #app.clipboard.fill((0,0,0,0))
712     #app.clipboard.blit(s,(0,0))
713     
714     print app.clipboard.get_at((0,0))
715     
716 def cmd_paste(value):
717     if app.clipboard != None:
718         app.archive()
719         #app.view.fill((0,0,0,0),(app.select[0],app.select[1],app.clipboard.get_width(),app.clipboard.get_height()))
720         #app.view.blit(app.clipboard,app.select)
721         #app.vdraw.repaint()
722         
723         rect,data = app.clipboard
724         rect = pygame.Rect(app.select.x,app.select.y,rect.w,rect.h)
725         
726         app.mod(rect)
727         app.paste(rect,data)
728         app.vdraw.repaint()
729
730 class Restart(Exception):
731     pass
732     
733 def _dirty(fnc,v):
734     dialog = DirtyDialog()
735     def onchange(value):
736         value.close()
737         return fnc(v)
738     dialog.connect(gui.CHANGE,onchange,dialog)
739     dialog.open()
740
741 def cmd_new(value):
742     if app.dirty: _dirty(_cmd_new,value)
743     else: _cmd_new(value)
744     
745 def _cmd_new(value):
746     dialog = NewDialog()
747     
748     def onchange(value):
749         value.close()
750         vv = value.value
751         ok = 0
752         try:        
753             width,height,tile_w,tile_h,codes,tiles,klass = int(vv['width'].value),int(vv['height'].value),int(vv['tile_w'].value),int(vv['tile_h'].value),vv['codes'].value,vv['tiles'].value,vv['class'].value
754             global cfg
755             cfg['fname'] = None
756             cfg['width'] = width
757             cfg['height'] = height
758             cfg['tile_w'] = tile_w
759             cfg['tile_h'] = tile_h
760             cfg['codes'] = codes
761             cfg['tiles'] = tiles
762             cfg['class'] = klass
763             ok = 1
764         except Exception, v:
765             ErrorDialog("New failed.",v).open()
766         if ok:
767             raise Restart()
768     
769     dialog.connect(gui.CHANGE,onchange,dialog)
770     dialog.open()
771
772     
773 def cmd_open(value):
774     if app.dirty: _dirty(_cmd_open,value)
775     else: _cmd_open(value)
776
777 def _cmd_open(value):
778     dialog = OpenDialog()
779     
780     def onchange(value):
781         value.close()
782         vv = value.value
783         ok = 0
784         
785         try:        
786             
787             fname,tile_w,tile_h,codes,tiles,klass = vv['fname'].value,int(vv['tile_w'].value),int(vv['tile_h'].value),vv['codes'].value,vv['tiles'].value,vv['class'].value
788             global cfg
789             cfg['fname'] = fname
790             cfg['tile_w'] = tile_w
791             cfg['tile_h'] = tile_h
792             cfg['codes'] = codes
793             cfg['tiles'] = tiles
794             cfg['class'] = klass
795
796             
797             ok = 1
798         except Exception,v:
799             ErrorDialog("Open failed.",v).open()
800             
801         if ok: raise Restart()
802
803     
804     dialog.connect(gui.CHANGE,onchange,dialog)
805     dialog.open()
806
807 def cmd_saveas(value):
808     dialog = SaveAsDialog()
809     
810     def onchange(value):
811         value.close()
812         vv = value.value
813         fname = vv['fname'].value
814         if len(fname) == 0:
815             ErrorDialog("Save As failed.","File Name too short!").open()
816             return
817         global cfg
818         app.fname = cfg['fname'] = fname
819         return cmd_save(None)
820         
821     dialog.connect(gui.CHANGE,onchange,dialog)
822     dialog.open()
823         
824 def cmd_cut(value):
825     cmd_copy(value)
826     cmd_delete(value)
827
828 def cmd_fullscreen(value):
829     pygame.display.toggle_fullscreen()
830     
831 def cmd_delete(value):
832     app.archive()
833     #app.view.fill((0,0,0,0),app.select)
834     app.mod(app.select)
835     app.fill(app.select,(0,0,0,0))
836     app.vdraw.repaint()
837         
838 #NOTE: this function is a temporary HACK, to be replaced
839 #with layer editing in the future, maybe.
840 def cmd_tswitch(value):
841     blayer = app.level.blayer
842     tlayer = app.level.tlayer
843     for ty in xrange(0,app.level.size[1]):
844         for tx in xrange(0,app.level.size[0]):
845             tmp = blayer[ty][tx]
846             blayer[ty][tx] = tlayer[ty][tx]
847             tlayer[ty][tx] = tmp
848     app.vdraw.repaint()
849     
850
851 def cmd_fill(value):
852     pass
853
854 def cmd_pick(value):
855     dx,dy = value
856     
857     mods = pygame.key.get_mods()
858     
859     
860     if (mods&KMOD_SHIFT) != 0:
861         app.level.view.x += dx*app.vdraw.rect.w/8
862         app.level.view.y += dy*app.vdraw.rect.h/8
863         app.vdraw.repaint()
864         #x,y = app.view.get_offset()
865         #x = x + 1*dx
866         #y = y + 1*dy
867         #x = min(max(x,0),app.level_w-app.view_w)
868         #y = min(max(y,0),app.level_h-app.view_h)
869         #app.view = app.level.subsurface((x,y,app.view_w,app.view_h))
870         
871     elif (mods&KMOD_CTRL) != 0:
872         app.level.view.x += dx*app.vdraw.rect.w
873         app.level.view.y += dy*app.vdraw.rect.h
874         app.vdraw.repaint()
875         #x,y = app.view.get_offset()
876         #x = x + app.view_w*dx
877         #y = y + app.view_h*dy
878         #x = min(max(x,0),app.level_w-app.view_w)
879         #y = min(max(y,0),app.level_h-app.view_h)
880         #app.view = app.level.subsurface((x,y,app.view_w,app.view_h))
881         
882     
883     else:
884         w = app.tiles_w/app.tile_w
885         if app.mode == 'code':
886             n = app.code + dx + dy*w
887             app.cpicker.set(n)
888         else:
889             n = app.tile + dx + dy*w
890             app.tpicker.set(n)
891         
892 def cmd_mode(value):
893     mode = value
894     app.mode = mode
895
896 def cmd_load(value):
897     if app.dirty: _dirty(_cmd_load,value)
898     else: _cmd_load(value)
899
900 def _cmd_load(value):
901     if app.fname == None:
902         ErrorDialog("Load failed","Image is untitled.").open()
903         return
904     raise Restart()
905
906     
907 def cmd_save(value):
908     if app.fname == None:
909         return cmd_saveas(value)
910     try:
911         app.level.tga_save_level(app.fname)
912         cfg_to_ini(['class','codes','tiles','tile_w','tile_h'],app.fname)
913         ini_save()
914         app.dirty = 0
915     except Exception, v:
916         ErrorDialog("Save failed.",v).open()
917         return
918
919     
920 import os
921 def cmd_preview(value):
922     app.level.tga_save_level("_preview.tga")
923     cmd = "python preview.py _preview.tga"
924     print cmd
925     os.system(cmd)
926     
927 def cmd_quit(value):
928     if app.dirty: _dirty(_cmd_quit,value)
929     else: _cmd_quit(value)
930
931 def _cmd_quit(value):
932     app.top.quit()    
933     
934 def cmd_refreshtiles(value):
935     app.load_tiles_and_codes()
936
937
938
939
940 menus = [
941     ('File/New',cmd_new,None),
942     ('File/Open',cmd_open,None),
943     ('File/Save',cmd_save,None),
944     ('File/Save As',cmd_saveas,None),
945     ('File/Reload',cmd_load,None),
946     ('File/Preview',cmd_preview,None),
947     ('File/Quit',cmd_quit,None),
948
949     ('Edit/Undo',cmd_undo,None),
950     ('Edit/Cut',cmd_cut,None),
951     ('Edit/Copy',cmd_copy,None),
952     ('Edit/Paste',cmd_paste,None),
953     ('Edit/Delete',cmd_delete,None),
954     ('Edit/Select All',cmd_all,None),
955     ('Edit/Shrink',cmd_shrink,None),
956     #('Edit/Redo',None,None,None),
957     #('Edit/Cut',None,None,None),
958     #('Edit/Fill',cmd_fill,None),
959     
960     ]
961
962 keys = [
963     (K_s,cmd_save,None),
964     (K_d,cmd_load,None),
965     (K_p,cmd_preview,None),
966
967     (K_a,cmd_all,None),
968     (K_z,cmd_undo,None),
969     #('Edit/Redo',None,None,None),
970     (K_x,cmd_cut,None),
971     (K_c,cmd_copy,None),
972     (K_v,cmd_paste,None),
973     #('Edit/Cut',None,None,None),
974     (K_DELETE,cmd_delete,None),
975     #(K_f,cmd_fill,None),
976         
977         (K_t,cmd_tswitch,None),
978     
979     (K_F10,cmd_fullscreen,None),
980     
981     (K_UP,cmd_pick,(0,-1)),
982     (K_DOWN,cmd_pick,(0,1)),
983     (K_LEFT,cmd_pick,(-1,0)),
984     (K_RIGHT,cmd_pick,(1,0)),
985     ]
986     
987
988 tools = [
989     ('tile','tile'),
990     ('bkgr','bkgr'),
991     ('code','code'),
992     ('select','select'),
993     ('eraser','eraser'),
994     ]
995
996     
997     
998
999 class NewDialog(gui.Dialog):
1000     def __init__(self,**params):
1001         title = gui.Label("New...")
1002         
1003         doc = html.HTML(globals={'gui':gui,'dialog':self},data="""
1004 <form id='form'>
1005
1006 <table>
1007
1008 <tr><td colspan=2>
1009
1010 <table>
1011 <tr><td>Level<br>Type:
1012 <td align=left><input type=radio name='class' value='pgu.tilevid.Tilevid' checked> Tile<br>
1013 <input type=radio name='class' value='pgu.isovid.Isovid'> Isometric<br>
1014 <input type=radio name='class' value='pgu.hexvid.Hexvid'> Hexoganol
1015
1016 <tr><td >Tiles: <td><input type='text' size=20 name='tiles' value='%(tiles)s'>
1017 <tr><td>Codes: <td><input type='text' size=20 name='codes' value='%(codes)s'>
1018 </table>
1019
1020 <tr>
1021 <td align=center>Level Size
1022 <td align=center>Tile Size
1023
1024
1025 <tr><td colspan='1' align='center' style='padding-right:8px;'>
1026 <table>
1027 <tr><td align=right>Width: <td><input type='text' size='4' value='%(width)s' name='width'>
1028 <tr><td align=right>Height: <td><input type='text' size='4' value='%(height)s' name='height'>
1029 </table>
1030
1031 <td colspan='1' align='center'>
1032 <table>
1033 <tr><td align=right>Width: <td><input type='text' size='4' value='%(tile_w)s' name='tile_w'>
1034 <tr><td align=right>Height: <td><input type='text' size='4' value='%(tile_h)s' name='tile_h'>
1035 </table>
1036
1037 <tr><td>&nbsp;
1038
1039 <tr><td colspan=2><input type='button' value='Okay' onclick='dialog.send(gui.CHANGE)'> <input type='button' value='Cancel' onclick='dialog.close()'>
1040
1041 </table>"""%ini_to_dict('None'))
1042         gui.Dialog.__init__(self,title,doc)
1043         
1044         self.value = doc['form']
1045
1046 class SaveAsDialog(gui.Dialog):
1047     def __init__(self,**params):
1048         title = gui.Label("Save As...")
1049         
1050         doc = html.HTML(globals={'gui':gui,'dialog':self},data="""
1051 <form id='form'>
1052
1053 <table>
1054
1055 <tr><td colspan=2>File Name: <input type='file' size=20 name='fname' value=''>
1056
1057 <tr><td>&nbsp;
1058
1059 <tr><td colspan=2><input type='button' value='Okay' onclick='dialog.send(gui.CHANGE)'> <input type='button' value='Cancel' onclick='dialog.close()'>
1060
1061 </table>""")
1062         gui.Dialog.__init__(self,title,doc)
1063         
1064         self.value = doc['form']
1065
1066 class OpenDialog(gui.Dialog):
1067     def __init__(self,**params):
1068         title = gui.Label("Open...")
1069         
1070         def load_vals(fname,form):
1071             if not ini.has_section(fname): return
1072             
1073             for k,v in ini.items(fname):
1074                 if k in form:
1075                     form[k].value = v
1076
1077         doc = html.HTML(globals={'load_vals':load_vals,'ini':ini,'gui':gui,'dialog':self},data="""<form id='form'><table>
1078         
1079         <tr><td align=right>File Name:&nbsp;<td  align=left><input type='file' size=20 name='fname' value='' onchange='load_vals(self.value,form)'>
1080
1081         <tr><td align=right>Level&nbsp;<br>Type:&nbsp;
1082         <td align=left><input type=radio name='class' value='pgu.tilevid.Tilevid' checked> Tile<br><input type=radio name='class' value='pgu.isovid.Isovid'> Isometric<br><input type=radio name='class' value='pgu.hexvid.Hexvid'> Hexoganol
1083         
1084         <tr><td align=right>Tiles:&nbsp;<td align=left><input type='text' size=20 name='tiles' value='%(tiles)s'>
1085         <tr><td align=right>Codes:&nbsp;<td align=left><input type='text' size=20 name='codes' value='%(codes)s'>
1086         
1087         <tr><td align=right>Tile Width:&nbsp;<td align=left><input type='text' size='4' value='%(tile_w)s' name='tile_w'>
1088         <tr><td align=right>Tile Height:&nbsp;<td align=left><input type='text' size='4' value='%(tile_h)s' name='tile_h'>
1089
1090
1091 <tr><td>&nbsp;
1092
1093 <tr><td colspan=2><input type='button' value='Okay' onclick='dialog.send(gui.CHANGE)'> <input type='button' value='Cancel' onclick='dialog.close()'>
1094
1095 </table>"""%ini_to_dict('None'))
1096         gui.Dialog.__init__(self,title,doc)
1097         
1098         self.value = doc['form']
1099
1100 class ErrorDialog(gui.Dialog):
1101     def __init__(self,tt,data,**params):
1102         title = gui.Label("Error: "+tt)
1103         data = str(data)
1104         
1105         doc = html.HTML(globals={'gui':gui,'dialog':self},data="""
1106 <form id='form'>
1107
1108 <table>
1109 <tr><td><h1>&lt;!&gt;&nbsp;</h1>
1110 <td>"""+data+"""
1111 <tr><td>&nbsp;
1112 <tr><td colspan=2><input type='button' value='Okay' onclick='dialog.send(gui.CHANGE);dialog.close()'>
1113 </table>""")
1114         gui.Dialog.__init__(self,title,doc)
1115         
1116         self.value = doc['form']
1117
1118 class DirtyDialog(gui.Dialog):
1119     def __init__(self,**params):
1120         title = gui.Label("File not yet saved...")
1121         data = "Your file is not yet saved.<br>Are you sure you want to continue?"
1122         
1123         doc = html.HTML(globals={'gui':gui,'dialog':self},data="""
1124 <form id='form'>
1125
1126 <table>
1127 <tr><td><h1>&lt;!&gt;&nbsp;</h1>
1128 <td>"""+data+"""
1129 <tr><td>&nbsp;
1130 <tr><td colspan=2><input type='button' value='Okay' onclick='dialog.send(gui.CHANGE)'> <input type='button' value='Cancel' onclick='dialog.close()'>
1131 </table>""")
1132         gui.Dialog.__init__(self,title,doc)
1133         
1134         self.value = doc['form']
1135
1136
1137     
1138         
1139 def init_ini():
1140     ini.read([ini_fname])
1141
1142 def ini_save():
1143     f = open(ini_fname,"wb")
1144     ini.write(f)
1145     f.close()
1146
1147
1148 def init_opts():
1149     ini.read([ini_fname])
1150     
1151     usage = "usage: %prog level.tga [tiles.tga] [codes.tga] [tile_w] [tile_h]"
1152     
1153     parser = OptionParser(usage)
1154     
1155     parser.add_option("-t", "--tiles", dest="tiles",
1156         help="filename of the tiles image (level)")
1157     parser.add_option("-c", "--codes", dest="codes",
1158         help="file name of the codes image (level)")
1159
1160     parser.add_option("--tw", dest="tile_w", help="tile width (level)", type='int')
1161     parser.add_option("--th", dest="tile_h", help="tile height (level)", type='int')
1162
1163     parser.add_option("--vw", dest="view_w", help="view width (level)", type='int')
1164     parser.add_option("--vh", dest="view_h", help="view height (level)", type='int')
1165         
1166     parser.add_option("--sw", dest="screen_w", help="screen width (app)", type='int')
1167     parser.add_option("--sh", dest="screen_h", help="screen height (app)", type='int')
1168     parser.add_option("--class",dest="class",help="class (e.g. pgu.tilevid.Tilevid) (level)")
1169     parser.add_option("--tile",action="store_const",const="pgu.tilevid.Tilevid",dest="class",help="use pgu.tilevid.Tilevid")
1170     parser.add_option("--iso",action="store_const",const="pgu.isovid.Isovid",dest="class",help="use pgu.isovid.Isovid")
1171     parser.add_option("--hex",action="store_const",const="pgu.hexvid.Hexvid",dest="class",help="use pgu.hexvid.Hexvid")
1172     
1173     parser.add_option("--width",dest="width",help="new width (level)",type='int')
1174     parser.add_option("--height",dest="height",help="new height (level)",type='int')
1175
1176     parser.add_option("-d","--defaults",dest="defaults",help="set default settings (image)",action="store_true")
1177
1178     #parser.add_option("-a", "--app", dest="app",
1179     #    help="set application level defaults", action="store_true")
1180     
1181     (opts, args) = parser.parse_args()
1182     
1183     if len(args) not in (0,1,2,3,4,5):
1184         parser.error("incorrect number of arguments")
1185     
1186     #parse arguments
1187     if len(args) == 0:
1188         opts.fname = "None"
1189     if len(args) > 0:
1190         opts.fname = args[0]
1191     if len(args) > 1:
1192         opts.tiles = args[1]
1193     if len(args) in (3,5):
1194         opts.codes = args[2]
1195     if len(args) in (4,5):
1196         n = len(args)-2
1197         try: opts.tile_w,opts.tile_h = int(args[n]),int(args[n+1])
1198         except: parser.error("width and height must be integers")
1199         if opts.tile_w < 1 or opts.tile_h < 1: parser.error("width and height must be greater than 0")
1200         
1201     fname = opts.fname
1202     
1203     #create all sections
1204     for k in [fname,"None","app"]:
1205         if not ini.has_section(k):
1206             ini.add_section(k)
1207     
1208     #set app level defaults
1209     for k,v in [('screen_w',800),('screen_h',600)]:
1210         if not ini.has_option('app',k):
1211             ini.set('app',k,str(v))
1212     
1213     #set app level values
1214     for k in ['screen_w','screen_h']:
1215         if hasattr(opts,k):
1216             v = getattr(opts,k)
1217             if v != None: ini.set('app',k,str(v))
1218
1219     #set default defaults
1220     for k,v in [('width',40),('height',30),('tile_w',32),('tile_h',32),('tiles','tiles.tga'),('codes','codes.tga'),('class','pgu.tilevid.Tilevid')]:
1221         if not ini.has_option('None',k):
1222             ini.set('None',k,str(v))
1223     
1224     #name of keys for normal stuff
1225     file_ks = ['class','tiles','codes','width','height','tile_w','tile_h']
1226             
1227     #set default values
1228     if opts.defaults:
1229         for k in file_ks:
1230             if hasattr(opts,k):
1231                 v = getattr(opts,k)
1232                 if v != None: ini.set('None',k,str(v))
1233     
1234     #set fname values
1235     for k in file_ks:
1236         if hasattr(opts,k):
1237             v = getattr(opts,k)
1238             if v != None: ini.set(fname,k,str(v))
1239     
1240     #save the ini
1241     ini_save()
1242             
1243     #convert ini to cfg stuff...
1244     ini_to_cfg(['app','None',fname])
1245     if fname == 'None': fname = None
1246     cfg['fname'] = fname
1247
1248 def ini_to_cfg(sections):
1249     global cfg
1250     ik = ['screen_w','screen_h','tile_w','tile_h','width','height']
1251     for s in sections:
1252         for k,v in ini.items(s):
1253             if k in ik: v = int(v)
1254             cfg[k] = v
1255
1256 def ini_to_dict(section):
1257     cfg = {}
1258     ik = ['screen_w','screen_h','tile_w','tile_h','width','height']
1259     for s in [section]:
1260         for k,v in ini.items(s):
1261             if k in ik: v = int(v)
1262             cfg[k] = v
1263     return cfg
1264
1265 def cfg_to_ini(ks,section):
1266     if not ini.has_section(section): ini.add_section(section)
1267     for k in ks:
1268         v = cfg[k]
1269         ini.set(section,k,str(v))
1270
1271         
1272 def init_gui():
1273     #themes = cfg['theme'].split(",")
1274 #    themes2 = []
1275 #    for t in themes:
1276 #        if t[0] == "/" or t[0] == ".": themes2.append(t)
1277 #        else: themes2.append(dname+"/"+t)
1278     #gui.theme.load(themes)
1279     #gui.theme.load(['default','tools'])
1280     global top
1281     top = gui.Desktop(theme=gui.Theme(['default','tools']))
1282     #top.theme.load(['default','tools'])
1283
1284
1285     pass
1286
1287 def init_app():
1288     global app
1289     app = _app()
1290     
1291     #
1292     ss = 8
1293         
1294     #--- top
1295     x,y,h = 0,0,0
1296         
1297     #menus
1298     e = gui.Menus(menus)
1299     e.rect.w,e.rect.h = e.resize()
1300     app.add(e,x,y)
1301     x,h = x+e.rect.w,max(h,e.rect.h)
1302     menus_height = e.rect.h
1303         
1304     #--- row
1305     x,y,h = 0,y+h,0
1306     
1307     #--- vspace
1308     y += ss
1309     
1310     #--- hspace
1311     x += ss
1312     
1313     #tools
1314     e = gui.Toolbox(tools,1,0,value='tile')#,"icons48")
1315     e.rect.w,e.rect.h = e.resize()
1316     def _set_mode(value): cmd_mode(value.value)
1317     e.connect(gui.CHANGE,_set_mode,e)
1318     app.add(e,x,y)
1319     app.tools = e.tools
1320     x,h = x+e.rect.w,max(h,e.rect.h)
1321     toolbox_width = e.rect.w
1322     
1323     #--- hspace
1324     x += ss
1325     
1326     #vdraw
1327     dw = app.screen_w - (toolbox_width+app.tiles.get_width()+ss*4)
1328     dh = app.screen_h - (menus_height+ss*2)
1329     app.view_init(dw,dh)
1330     
1331     
1332     e = app.vwrap = vwrap()
1333     app.vdraw = e.vdraw
1334     e.rect.w,e.rect.h = e.resize()
1335     app.add(e,x,y)
1336     x,h = x+e.rect.w,max(h,e.rect.h)
1337     
1338     #--- hspace
1339     x += ss
1340     
1341     #tpicker
1342     e = app.tpicker = tpicker()
1343     e.rect.w,e.rect.h = e.resize()
1344     #--- right
1345     x = app.screen_w-e.rect.w-ss
1346     app.add(e,x,y)
1347     x,h = x+e.rect.w,max(h,e.rect.h)
1348     tpicker_height = e.rect.h
1349     
1350     #cpicker
1351     e = app.cpicker = cpicker()
1352     e.rect.w,e.rect.h = e.resize()
1353     #--- right
1354     x = app.screen_w-e.rect.w-ss
1355     app.add(e,x,y+tpicker_height+ss)
1356     x,h = x+e.rect.w,max(h,e.rect.h)
1357     
1358
1359
1360
1361     pygame.key.set_repeat(500,30)
1362     
1363     app.screen.fill((255,255,255,255))
1364
1365
1366 def run():
1367     top.connect(gui.QUIT,cmd_quit,None)
1368     top.connect(pygame.ACTIVEEVENT, cmd_refreshtiles,None)
1369
1370     top.init(app,app.screen)
1371     app.top=top
1372     top.run()
1373
1374 def main():
1375     init_ini()
1376     init_opts()
1377     init_gui()
1378     
1379     restart = 1
1380     while restart:
1381         restart = 0
1382         try:
1383             init_app()
1384             run()
1385         except Restart: restart = 1
1386
1387 main()
1388 # vim: set filetype=python sts=4 sw=4 noet si :

UCC git Repository :: git.ucc.asn.au