1 #!C:\Python32\python.exe
2 """<title>a simple level editor for pygame</title>
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]
8 -h, --help show this help message and exit
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
26 leveledit level.tga tiles.tga codes.tga 16 16
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.
33 you may edit default options in leveledit.ini
36 - menus for common commands
39 left click to use current tool
40 right click to select a tile
41 middle drag to move around the level
43 click to select a tile
45 click to select a code
54 c - copy selection to clipboard
55 v - paste clipboard at selection origin
56 delete - delete selection
59 t - switch tile & bkgr layers
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
69 from optparse import OptionParser
70 from ConfigParser import ConfigParser
72 from pygame.locals import *
74 # the following line is not needed if pgu is installed
75 import sys; sys.path.insert(0, "..")
77 from pgu import gui, html, tilevid, isovid, hexvid
82 ini_fname = "leveledit.ini"
86 class _app(gui.Container):
88 gui.Container.__init__(self)
90 #self.background = gui.Box(self.style.background)
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)
97 self.fname = cfg['fname']
101 n = ".".join(parts[:-1])
102 m = __import__(n,globals(),locals(),parts[-1])
103 c = getattr(m,parts[-1])
106 #self.level = pygame.image.load(self.level_fname)
107 #self.level = tilevid.Tilevid()
108 #g = self.level = isovid.Isovid()
111 if self.fname != None:
112 self.level.tga_load_level(self.fname,1)
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)
118 self.tiles_last_ctime = None
119 self.codes_last_ctime = None
121 self.load_tiles_and_codes()
132 self.clipboard = None
134 #self.modrect = pygame.Rect(0xffff,0xffff,-0xffff,-0xffff)
140 def load_tiles_and_codes(self):
144 self.tile_w, self.tile_h = cfg['tile_w'], cfg['tile_h']
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.
150 newctime = os.stat(self.tiles_fname)[9]
151 if newctime <= self.tiles_last_ctime:
152 #nothing to do, so we return.
155 self.tiles_last_ctime = newctime
157 self.tiles = pygame.image.load(self.tiles_fname)
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))
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.
170 self.codes_last_ctime = newctime
172 self.codes = pygame.image.load(self.codes_fname)
174 self.codes = hex_image(self)
176 self.codes_w, self.codes_h = (self.codes.get_width(),
177 self.codes.get_height())
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
193 self.changes.append((pygame.Rect(rect),self.copy(rect)))
196 def view_init(self,dw,dh):
198 self.view_w = dw #/ self.tile_w
199 self.view_h = dh #/ self.tile_h
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'])
206 #self.view_w = min(self.level.size[0],self.view_w)
207 #self.view_h = min(self.level.size[1],self.view_h)
209 #print self.view_w,self.view_h
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)
214 def fill(self,rect,v):
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]
225 data = [[[None for x in range(0,rect.w)] for y in range(0,rect.h)] for l in range(0,4)]
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]
237 def paste(self,rect,data):
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
246 if v != None and tx >= 0 and tx < w and ty >= 0 and ty < h: layer[ty][tx] = v
250 if not len(self.changes): return
256 #c = pygame.Surface((self.view_w,self.view_h),SWSURFACE,self.view)
258 #c.blit(self.view,(0,0))
261 #ox,oy = lvl.screen_to_tile((0,0))
262 #bx,by = lvl.screen_to_tile((self.vdraw.rect.w,self.vdraw.rect.h))
264 #rect = pygame.Rect(ox,oy,bx-ox,by-oy)
267 h.append(self.changes)
271 if len(self.changes): self.archive()
273 if len(self.history) == 0: return
276 changes = self.history.pop()
279 for rect,data in changes:
280 self.paste(rect,data)
283 self.tpicker.repaint() #huh?
288 self.level.fill((0,0,0,0),(off[0],off[1],self.view_w,self.view_h))
289 self.level.blit(c,off)
291 self.tpicker.repaint()
293 def __setattr__(self,k,v):
297 if hasattr(self,'vdraw'): self.vdraw.repaint()
300 if hasattr(self,'tpicker'): self.tpicker.repaint()
303 if hasattr(self,'cpicker'): self.cpicker.repaint()
307 if e.type is KEYDOWN:
308 for key,cmd,value in keys:
312 return gui.Container.event(self,e)
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()
320 w,h = self.tiles_w / self.tile_w, self.tiles_h / self.tile_h
322 fnt = pygame.font.SysFont("helvetica",self.tile_h-1)
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))
337 class tpicker(gui.Widget):
339 gui.Widget.__init__(self)
340 self.style.width = app.tiles_w
341 self.style.height = app.tiles_h
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)
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
357 if app.mode not in ('tile','bkgr'):
358 app.tools['tile'].click()
361 if n < 0 or n >= len(app.level.tiles) or app.level.tiles[n] == None: return
365 class cpicker(gui.Widget):
367 gui.Widget.__init__(self)
368 self.style.width = app.codes_w
369 self.style.height = app.codes_h
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)
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
385 app.tools['code'].click()
388 if n < 0 or n >= len(app.level.codes) or app.level.codes[n] == None: return
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
402 self.vdraw = e = vdraw(width=w-sw,height=h-sw)
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)]
409 minx,miny,maxx,maxy = 0xffff,0xffff,-0xffff,-0xffff
411 minx,miny,maxx,maxy = min(minx,x),min(miny,y),max(maxx,x),max(maxy,y)
418 self.vs = e = gui.VSlider(0,miny,maxy,sw*4,width=sw,height=h-sw)
420 e.connect(gui.CHANGE,self.move_y,e)
422 self.hs = e = gui.HSlider(0,minx,maxx,sw*4,width=w-sw,height=sw)
424 e.connect(gui.CHANGE,self.move_x,e)
426 def move_x(self,value):
428 if app.level.view.x != v:
432 def move_y(self,value):
434 if app.level.view.y != v:
439 self.vs.value = app.level.view.y
440 self.hs.value = app.level.view.x
443 class vdraw(gui.Widget):
445 self.container.adjust()
446 gui.Widget.repaint(self)
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
454 s = pygame.Surface((self.rect.w,self.rect.h))
455 clrs = [(148,148,148),(108,108,108)]
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))
462 s = pygame.Surface((self.rect.w,self.rect.h)).convert_alpha()
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))
475 #print s.get_width(),s.get_height(),s.get_clip()
476 #s.blit(self.bg,(0,0))
477 s.fill((128,128,128))
479 #make sure to clamp the bounds
480 if app.level.bounds != None:
481 app.level.view.clamp_ip(app.level.bounds)
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)
494 tmp_tiles = app.level.tiles
495 tmp_tlayer = app.level.tlayer
496 tmp_blayer = app.level.blayer
498 app.level.tiles = app.level.codes
499 app.level.tlayer = app.level.clayer
500 app.level.blayer = None
504 app.level.tiles = tmp_tiles
505 app.level.tlayer = tmp_tlayer
506 app.level.blayer = tmp_blayer
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)
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)
521 #s.blit(self.grid,(0,0))
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)
526 if e.type is MOUSEMOTION:
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):
530 if e.type is MOUSEBUTTONDOWN and e.button == 1:
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:
539 if hasattr(self,a): getattr(self,a)(e)
540 if e.type is MOUSEBUTTONDOWN and e.button == 2:
542 if e.type is MOUSEMOTION and e.buttons[1] and self.container.myfocus == self:
546 def move_down(self,e):
547 self.moff = app.level.view.x,app.level.view.y
550 def move_drag(self,e):
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]
558 def picker_down(self,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
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]
574 def tile_down(self,e):
578 def tile_drag(self,e):
580 #r,g,b,a = app.view.get_at(pos)
582 #app.view.set_at(pos,(r,g,b))
584 if pos == None: return
586 app.mod(pygame.Rect(tx,ty,1,1))
587 app.level.tlayer[ty][tx] = app.tile
591 def bkgr_down(self,e):
595 def bkgr_drag(self,e):
597 #r,g,b,a = app.view.get_at(pos)
599 #app.view.set_at(pos,(r,g,b))
600 if pos == None: return
602 app.mod(pygame.Rect(tx,ty,1,1))
603 app.level.blayer[ty][tx] = app.tile
608 def code_down(self,e):
612 def code_drag(self,e):
614 #r,g,b,a = app.view.get_at(pos)
616 #app.view.set_at(pos,(r,g,b))
617 if pos == None: return
619 app.mod(pygame.Rect(tx,ty,1,1))
620 app.level.clayer[ty][tx] = app.code
624 def eraser_down(self,e):
628 def eraser_drag(self,e):
630 if pos == None: return
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))
640 tx,ty = app.level.screen_to_tile(e.pos)
642 if tx < 0 or ty < 0 or tx >= app.level.size[0] or ty >= app.level.size[1]: return None
644 if (tx,ty) != self.pos:
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)
655 tx,ty = app.level.screen_to_tile(e.pos)
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)
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)
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)
683 app.select = Rect(0,0,app.level.size[0],app.level.size[1])
686 #print 'deprecated in v0.5'
688 def cmd_shrink(value):
689 if app.select.w <= 2 or app.select.h <= 2: return
702 #next version of pygame?
703 #app.clipboard = app.tile.subsurface(app.select).copy()
705 data = app.copy(app.select)
706 app.clipboard = pygame.Rect(app.select),data
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))
714 print app.clipboard.get_at((0,0))
716 def cmd_paste(value):
717 if app.clipboard != None:
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)
723 rect,data = app.clipboard
724 rect = pygame.Rect(app.select.x,app.select.y,rect.w,rect.h)
730 class Restart(Exception):
734 dialog = DirtyDialog()
738 dialog.connect(gui.CHANGE,onchange,dialog)
742 if app.dirty: _dirty(_cmd_new,value)
743 else: _cmd_new(value)
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
757 cfg['height'] = height
758 cfg['tile_w'] = tile_w
759 cfg['tile_h'] = tile_h
765 ErrorDialog("New failed.",v).open()
769 dialog.connect(gui.CHANGE,onchange,dialog)
774 if app.dirty: _dirty(_cmd_open,value)
775 else: _cmd_open(value)
777 def _cmd_open(value):
778 dialog = OpenDialog()
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
790 cfg['tile_w'] = tile_w
791 cfg['tile_h'] = tile_h
799 ErrorDialog("Open failed.",v).open()
801 if ok: raise Restart()
804 dialog.connect(gui.CHANGE,onchange,dialog)
807 def cmd_saveas(value):
808 dialog = SaveAsDialog()
813 fname = vv['fname'].value
815 ErrorDialog("Save As failed.","File Name too short!").open()
818 app.fname = cfg['fname'] = fname
819 return cmd_save(None)
821 dialog.connect(gui.CHANGE,onchange,dialog)
828 def cmd_fullscreen(value):
829 pygame.display.toggle_fullscreen()
831 def cmd_delete(value):
833 #app.view.fill((0,0,0,0),app.select)
835 app.fill(app.select,(0,0,0,0))
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]):
846 blayer[ty][tx] = tlayer[ty][tx]
857 mods = pygame.key.get_mods()
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
864 #x,y = app.view.get_offset()
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))
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
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))
884 w = app.tiles_w/app.tile_w
885 if app.mode == 'code':
886 n = app.code + dx + dy*w
889 n = app.tile + dx + dy*w
897 if app.dirty: _dirty(_cmd_load,value)
898 else: _cmd_load(value)
900 def _cmd_load(value):
901 if app.fname == None:
902 ErrorDialog("Load failed","Image is untitled.").open()
908 if app.fname == None:
909 return cmd_saveas(value)
911 app.level.tga_save_level(app.fname)
912 cfg_to_ini(['class','codes','tiles','tile_w','tile_h'],app.fname)
916 ErrorDialog("Save failed.",v).open()
921 def cmd_preview(value):
922 app.level.tga_save_level("_preview.tga")
923 cmd = "python preview.py _preview.tga"
928 if app.dirty: _dirty(_cmd_quit,value)
929 else: _cmd_quit(value)
931 def _cmd_quit(value):
934 def cmd_refreshtiles(value):
935 app.load_tiles_and_codes()
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),
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),
965 (K_p,cmd_preview,None),
969 #('Edit/Redo',None,None,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),
977 (K_t,cmd_tswitch,None),
979 (K_F10,cmd_fullscreen,None),
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)),
999 class NewDialog(gui.Dialog):
1000 def __init__(self,**params):
1001 title = gui.Label("New...")
1003 doc = html.HTML(globals={'gui':gui,'dialog':self},data="""
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
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'>
1021 <td align=center>Level Size
1022 <td align=center>Tile Size
1025 <tr><td colspan='1' align='center' style='padding-right:8px;'>
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'>
1031 <td colspan='1' align='center'>
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'>
1039 <tr><td colspan=2><input type='button' value='Okay' onclick='dialog.send(gui.CHANGE)'> <input type='button' value='Cancel' onclick='dialog.close()'>
1041 </table>"""%ini_to_dict('None'))
1042 gui.Dialog.__init__(self,title,doc)
1044 self.value = doc['form']
1046 class SaveAsDialog(gui.Dialog):
1047 def __init__(self,**params):
1048 title = gui.Label("Save As...")
1050 doc = html.HTML(globals={'gui':gui,'dialog':self},data="""
1055 <tr><td colspan=2>File Name: <input type='file' size=20 name='fname' value=''>
1059 <tr><td colspan=2><input type='button' value='Okay' onclick='dialog.send(gui.CHANGE)'> <input type='button' value='Cancel' onclick='dialog.close()'>
1062 gui.Dialog.__init__(self,title,doc)
1064 self.value = doc['form']
1066 class OpenDialog(gui.Dialog):
1067 def __init__(self,**params):
1068 title = gui.Label("Open...")
1070 def load_vals(fname,form):
1071 if not ini.has_section(fname): return
1073 for k,v in ini.items(fname):
1077 doc = html.HTML(globals={'load_vals':load_vals,'ini':ini,'gui':gui,'dialog':self},data="""<form id='form'><table>
1079 <tr><td align=right>File Name: <td align=left><input type='file' size=20 name='fname' value='' onchange='load_vals(self.value,form)'>
1081 <tr><td align=right>Level <br>Type:
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
1084 <tr><td align=right>Tiles: <td align=left><input type='text' size=20 name='tiles' value='%(tiles)s'>
1085 <tr><td align=right>Codes: <td align=left><input type='text' size=20 name='codes' value='%(codes)s'>
1087 <tr><td align=right>Tile Width: <td align=left><input type='text' size='4' value='%(tile_w)s' name='tile_w'>
1088 <tr><td align=right>Tile Height: <td align=left><input type='text' size='4' value='%(tile_h)s' name='tile_h'>
1093 <tr><td colspan=2><input type='button' value='Okay' onclick='dialog.send(gui.CHANGE)'> <input type='button' value='Cancel' onclick='dialog.close()'>
1095 </table>"""%ini_to_dict('None'))
1096 gui.Dialog.__init__(self,title,doc)
1098 self.value = doc['form']
1100 class ErrorDialog(gui.Dialog):
1101 def __init__(self,tt,data,**params):
1102 title = gui.Label("Error: "+tt)
1105 doc = html.HTML(globals={'gui':gui,'dialog':self},data="""
1109 <tr><td><h1><!> </h1>
1112 <tr><td colspan=2><input type='button' value='Okay' onclick='dialog.send(gui.CHANGE);dialog.close()'>
1114 gui.Dialog.__init__(self,title,doc)
1116 self.value = doc['form']
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?"
1123 doc = html.HTML(globals={'gui':gui,'dialog':self},data="""
1127 <tr><td><h1><!> </h1>
1130 <tr><td colspan=2><input type='button' value='Okay' onclick='dialog.send(gui.CHANGE)'> <input type='button' value='Cancel' onclick='dialog.close()'>
1132 gui.Dialog.__init__(self,title,doc)
1134 self.value = doc['form']
1140 ini.read([ini_fname])
1143 f = open(ini_fname,"wb")
1149 ini.read([ini_fname])
1151 usage = "usage: %prog level.tga [tiles.tga] [codes.tga] [tile_w] [tile_h]"
1153 parser = OptionParser(usage)
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)")
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')
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')
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")
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')
1176 parser.add_option("-d","--defaults",dest="defaults",help="set default settings (image)",action="store_true")
1178 #parser.add_option("-a", "--app", dest="app",
1179 # help="set application level defaults", action="store_true")
1181 (opts, args) = parser.parse_args()
1183 if len(args) not in (0,1,2,3,4,5):
1184 parser.error("incorrect number of arguments")
1190 opts.fname = args[0]
1192 opts.tiles = args[1]
1193 if len(args) in (3,5):
1194 opts.codes = args[2]
1195 if len(args) in (4,5):
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")
1203 #create all sections
1204 for k in [fname,"None","app"]:
1205 if not ini.has_section(k):
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))
1213 #set app level values
1214 for k in ['screen_w','screen_h']:
1217 if v != None: ini.set('app',k,str(v))
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))
1224 #name of keys for normal stuff
1225 file_ks = ['class','tiles','codes','width','height','tile_w','tile_h']
1232 if v != None: ini.set('None',k,str(v))
1238 if v != None: ini.set(fname,k,str(v))
1243 #convert ini to cfg stuff...
1244 ini_to_cfg(['app','None',fname])
1245 if fname == 'None': fname = None
1246 cfg['fname'] = fname
1248 def ini_to_cfg(sections):
1250 ik = ['screen_w','screen_h','tile_w','tile_h','width','height']
1252 for k,v in ini.items(s):
1253 if k in ik: v = int(v)
1256 def ini_to_dict(section):
1258 ik = ['screen_w','screen_h','tile_w','tile_h','width','height']
1260 for k,v in ini.items(s):
1261 if k in ik: v = int(v)
1265 def cfg_to_ini(ks,section):
1266 if not ini.has_section(section): ini.add_section(section)
1269 ini.set(section,k,str(v))
1273 #themes = cfg['theme'].split(",")
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'])
1281 top = gui.Desktop(theme=gui.Theme(['default','tools']))
1282 #top.theme.load(['default','tools'])
1298 e = gui.Menus(menus)
1299 e.rect.w,e.rect.h = e.resize()
1301 x,h = x+e.rect.w,max(h,e.rect.h)
1302 menus_height = e.rect.h
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)
1320 x,h = x+e.rect.w,max(h,e.rect.h)
1321 toolbox_width = e.rect.w
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)
1332 e = app.vwrap = vwrap()
1334 e.rect.w,e.rect.h = e.resize()
1336 x,h = x+e.rect.w,max(h,e.rect.h)
1342 e = app.tpicker = tpicker()
1343 e.rect.w,e.rect.h = e.resize()
1345 x = app.screen_w-e.rect.w-ss
1347 x,h = x+e.rect.w,max(h,e.rect.h)
1348 tpicker_height = e.rect.h
1351 e = app.cpicker = cpicker()
1352 e.rect.w,e.rect.h = e.resize()
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)
1361 pygame.key.set_repeat(500,30)
1363 app.screen.fill((255,255,255,255))
1367 top.connect(gui.QUIT,cmd_quit,None)
1368 top.connect(pygame.ACTIVEEVENT, cmd_refreshtiles,None)
1370 top.init(app,app.screen)
1385 except Restart: restart = 1
1388 # vim: set filetype=python sts=4 sw=4 noet si :