6d3e3672c159c6fe4eab56344031a340f502125a
[matches/honours.git] / research / transmission_spectroscopy / simulator / pgu-0.18 / scripts / tileedit
1 #!/usr/bin/python
2 """<title>a simple tile editor for pygame</title>
3 <pre>
4
5 usage: tileedit tiles.tga [tile_w] [tile_h]
6 windows: python tileedit tiles.tga [tile_w] [tile_h]
7
8 options:
9   -h, --help            show this help message and exit
10   --sw=SCREEN_W         screen width (app)
11   --sh=SCREEN_H         screen height (app)
12   --tw=TILE_W           tile width (image)
13   --th=TILE_H           tile height (image)
14   --width=WIDTH         new width (image)
15   --height=HEIGHT       new height (image)
16   -pPALETTE, --pal=PALETTE
17                         filename of palette (image)
18   -d, --defaults        set default settings (image)
19
20 example:
21 tileedit tiles.tga 16 16
22
23 note:
24 the editor can only edit tga files.
25
26 you may edit default options in tileedit.ini
27
28 interface:
29 - menus for common commands
30 - toolbox
31 - tile edit area
32     left click to use current tool
33     right click to select color
34 - tile select area
35     left click to select a tile
36     right click to select any region
37 - color select area
38     click to select a color
39
40 keys:
41 s - save
42 d - reload
43
44 z - undo
45 x - cut selection
46 c - copy selection
47 v - paste clipboard
48 delete - delete selection
49 f - fill selection
50 e - draw ellipse in selection
51 a - select all
52
53 [ - rotate -90
54 ] - rotate +90
55 , - flip horizontal
56 . - flip vertical
57
58 arrows - change tile
59 F10 - toggle fullscreen
60 </pre>
61 """
62
63 import os,sys    
64 from optparse import OptionParser
65 from ConfigParser import ConfigParser
66 import pygame
67 from pygame.locals import *
68
69 # try:
70 #     import Image
71 #     have_pil=True
72 # except:
73 #     print "import Image failure; PIL not found."
74 #     have_pil=False
75
76 have_pil = False
77
78 # the following line is not needed if pgl is installed
79 import sys; sys.path.insert(0, "..")
80 import shutil
81
82 from pgu import gui, html
83
84
85 #whatever...
86 ini_fname = "tileedit.ini"
87 ini = ConfigParser()
88
89 cfg = {}
90
91 class _app(gui.Container):
92     def __init__(self):
93         gui.Container.__init__(self)
94         #self.cls = "desktop"
95         #self.background = gui.Box(self.style.background)
96         
97         self.screen_w = cfg['screen_w']
98         self.screen_h = cfg['screen_h']
99         self.screen = pygame.display.set_mode((self.screen_w,self.screen_h),SWSURFACE)
100         
101         self.fname = cfg['fname']
102
103         if self.fname != None:
104             if have_pil==True:
105
106                 im = Image.open(self.fname)
107                 mode = im.mode
108                 size = im.size
109                 data = im.tostring()
110
111                 assert mode in ("RGB", "RGBA")
112
113                 self.tiles = pygame.image.fromstring(data, size, mode)
114
115             else:
116                 self.tiles = pygame.image.load(self.fname) # old tga-only method
117         else:
118             w,h = cfg['width'],cfg['height']
119             s = pygame.Surface((w,h),SWSURFACE|SRCALPHA,32)
120             s.fill((0,0,0,0))
121             self.tiles = s
122
123         self.tiles_w, self.tiles_h = self.tiles.get_width(),self.tiles.get_height()
124             
125         
126         self.tile_w, self.tile_h = cfg['tile_w'],cfg['tile_h'] 
127         self.tile = self.tiles.subsurface((0,0,self.tile_w,self.tile_h))
128         
129         self.color = (255,255,255,255)
130         self.mode = 'draw'
131         self.clipboard = None
132         self.select = Rect(0,0,self.tile_w,self.tile_h)
133         self.history = []
134         self.dirty = 0
135         
136     def archive(self):
137         h = self.history
138         if len(h) >= 32:
139             del h[0]
140         c = pygame.Surface((self.tile_w,self.tile_h),SWSURFACE,self.tile)
141         c.fill((0,0,0,0))
142         c.blit(self.tile,(0,0))
143         h.append((c,self.tile.get_offset()))
144         self.dirty = 1
145         
146     def undo(self):
147         if len(self.history) == 0: return
148         c,off = self.history.pop()
149         self.tiles.fill((0,0,0,0),(off[0],off[1],self.tile_w,self.tile_h))
150         self.tiles.blit(c,off)
151         self.tdraw.repaint()
152         self.tpicker.repaint()
153         self.dirty = 1
154         
155     def __setattr__(self,k,v):
156         self.__dict__[k] = v
157         
158         if k == 'color':
159             if hasattr(self,'cpreview'): self.cpreview.repaint()
160         if k == 'tile':
161             if hasattr(self,'tdraw'): self.tdraw.repaint()
162             if hasattr(self,'tpicker'): self.tpicker.repaint()
163             if hasattr(self,'tpreview'): self.tpreview.repaint()
164     def event(self,e):
165         if e.type is KEYDOWN:
166             for key,cmd,value in keys:
167                 if e.key == key:
168                     cmd(value)
169                     return
170         return gui.Container.event(self,e)
171     
172 class cpreview(gui.Widget):
173     def __init__(self,w,h):
174         gui.Widget.__init__(self)
175         self.style.width = w 
176         self.style.height = h
177         
178     def paint(self,s):
179         s.fill((128,128,128))
180         s.fill(app.color)
181
182         
183 class cpicker(gui.Widget):
184     def __init__(self,w,h,pal):
185         gui.Widget.__init__(self)
186         self.style.width = w
187         self.style.height = h
188         self.palette = pal
189         self.palette_w = pal.get_width()
190         self.palette_h = pal.get_height()
191     
192     def paint(self,s):
193         s.blit(pygame.transform.scale(self.palette,(self.rect.w,self.rect.h)),(0,0))
194             
195     def event(self,e):
196         if (e.type is MOUSEBUTTONDOWN) or (e.type is MOUSEMOTION and e.buttons[0] == 1 and self.container.myfocus == self):
197             x,y = e.pos[0]*self.palette_w/self.rect.w,e.pos[1]*self.palette_h/self.rect.h
198             x,y = max(0,x),max(0,y)
199             x,y = min(self.palette_w-1,x),min(self.palette_h-1,y)
200         
201             app.color = self.palette.get_at((x,y))
202
203 class tpicker(gui.Widget):
204     def __init__(self):
205         gui.Widget.__init__(self)
206         self.style.width = app.tiles_w
207         self.style.height = app.tiles_h
208         
209     def paint(self,s):
210         s.fill((128,128,128))
211         s.blit(app.tiles,(0,0))
212         off = app.tile.get_offset()
213         pygame.draw.rect(s,(255,255,255),(off[0],off[1],app.tile_w,app.tile_h),2)
214         
215     def pick(self,pos):
216         x,y = pos
217         while x < 0: x += self.rect.w
218         while y < 0: y += self.rect.h
219         while x >= self.rect.w: x -= self.rect.w
220         while y >= self.rect.h: y -= self.rect.h
221         app.tile = app.tiles.subsurface((x,y,app.tile_w,app.tile_h))
222
223     def event(self,e):
224         if (e.type is MOUSEBUTTONDOWN and e.button == 1) or (e.type is MOUSEMOTION and e.buttons[0] == 1 and self.container.myfocus == self):
225             x,y = e.pos[0]/app.tile_w*app.tile_w,e.pos[1]/app.tile_h*app.tile_h
226             self.pick((x,y))
227             
228         if (e.type is MOUSEBUTTONDOWN and e.button == 3) or (e.type is MOUSEMOTION and e.buttons[2] == 1 and self.container.myfocus == self):
229             x,y = e.pos[0]-app.tile_w/2,e.pos[1]-app.tile_h/2
230             x = min(self.rect.w-app.tile_w-1,max(0,x))
231             y = min(self.rect.h-app.tile_h-1,max(0,y))
232             self.pick((x,y))
233
234 class tpreview(gui.Widget):
235     def __init__(self):
236         gui.Widget.__init__(self)
237         self.style.width = app.tile_w*3
238         self.style.height = app.tile_h*3
239     def paint(self, s):
240         atw = app.tile_w
241         ath = app.tile_h
242         s.fill((100,100,100))
243         s.blit(app.tile,(0,0))
244         s.blit(app.tile,(1*atw,0))
245         s.blit(app.tile,(2*atw,0))
246         s.blit(app.tile,(0,1*ath))
247         s.blit(app.tile,(1*atw,1*ath))
248         s.blit(app.tile,(2*atw,1*ath))
249         s.blit(app.tile,(0,2*ath))
250         s.blit(app.tile,(1*atw,2*ath))
251         s.blit(app.tile,(2*atw,2*ath))        
252
253 class tdraw(gui.Widget):
254     def __init__(self,w,h):
255         gui.Widget.__init__(self)
256         self.rect.w = self.style.width = w
257         self.rect.h = self.style.height = h
258         self.overlay = pygame.Surface((app.tile_w,app.tile_h)).convert_alpha()
259         self.overlay.fill((0,0,0,0))
260         s = pygame.Surface((self.rect.w,self.rect.h))
261         clrs = [(148,148,148),(108,108,108)]
262         for y in range(0,app.tile_h*2):
263             for x in range(0,app.tile_w*2):
264                 s.fill(clrs[(x+y)%2],(
265                     self.rect.w*x/(app.tile_w*2),
266                     self.rect.h*y/(app.tile_h*2),
267                     self.rect.w/(app.tile_w*2)+1,
268                     self.rect.h/(app.tile_h*2)+2))
269         self.bg = s
270
271         s = pygame.Surface((self.rect.w,self.rect.h)).convert_alpha()
272         s.fill((0,0,0,0))
273         for x in range(0,app.tile_w):
274             pygame.draw.line(s,(0,0,0),(self.rect.w*x/app.tile_w,0),(self.rect.w*x/app.tile_w,self.rect.h))
275         for y in range(0,app.tile_h):
276             pygame.draw.line(s,(0,0,0),(0,self.rect.h*y/app.tile_h),(self.rect.w,self.rect.h*y/app.tile_h))
277         self.grid = s
278
279         
280     def paint(self,s):
281         s.blit(self.bg,(0,0))
282         s.blit(pygame.transform.scale(app.tile,(self.rect.w,self.rect.h)),(0,0))
283         s.blit(pygame.transform.scale(self.overlay,(self.rect.w,self.rect.h)),(0,0))
284         #if app.mode == 'select':
285         s.blit(self.grid,(0,0))
286         r = app.select
287         pygame.draw.rect(s,(255,255,255,128),Rect(r.x*self.rect.w/app.tile_w,r.y*self.rect.h/app.tile_h,r.w*self.rect.w/app.tile_w,r.h*self.rect.h/app.tile_h),4)
288         
289     def event(self,e):
290         if (e.type is MOUSEBUTTONDOWN and e.button == 3) or (e.type is MOUSEMOTION and e.buttons[2]==1 and self.container.myfocus == self):
291             self.picker_down(e)
292         if e.type is MOUSEBUTTONDOWN and e.button == 1:
293             a = '%s_down'%app.mode
294             if hasattr(self,a): getattr(self,a)(e)
295         if e.type is MOUSEMOTION and e.buttons[0] and self.container.myfocus == self:
296             a = '%s_drag'%app.mode
297             if hasattr(self,a): getattr(self,a)(e)
298         if e.type is MOUSEBUTTONUP and e.button == 1:
299             a = '%s_up'%app.mode
300             if hasattr(self,a): getattr(self,a)(e)
301             
302     #picker
303     def picker_down(self,e):
304         pos = self.getpos(e)
305         c = app.tile.get_at(pos)
306         app.color = c
307     
308     #fill
309     def fill_down(self,e):
310         app.archive()
311         pos = self.getpos(e)
312         bg = app.tile.get_at(pos)
313         if bg == app.color: return
314         self.fill_pixel(pos,bg)
315         self.repaint()
316         
317         
318     def fill_pixel(self,pos,bg): #worst algorithm
319         c = app.tile.get_at(pos)
320         if c != bg: return
321         app.tile.set_at(pos,app.color)
322         x,y = pos
323         if x > 0: self.fill_pixel((x-1,y),bg)
324         if x < app.tile_w-1: self.fill_pixel((x+1,y),bg)
325         if y > 0: self.fill_pixel((x,y-1),bg)
326         if y < app.tile_h-1: self.fill_pixel((x,y+1),bg)
327         
328     #pixel        
329     def pixel_down(self,e):
330         app.archive()
331         pos = self.getpos(e)
332         app.tile.set_at(pos,app.color)
333         self.repaint()
334         
335     #line
336     def line_down(self,e):
337         pos = self.getpos(e)
338         self.pos = pos
339         
340     def line_drag(self,e):
341         self.overlay.fill((0,0,0,0))
342         pos = self.getpos(e)
343         pygame.draw.line(self.overlay,app.color,self.pos,pos)
344         self.repaint()
345     
346     def line_up(self,e):
347         app.archive()
348         self.overlay.fill((0,0,0,0))
349         pos = self.getpos(e)
350         pygame.draw.line(app.tile,app.color,self.pos,pos)
351         self.repaint()
352         
353     #ellipse
354     def ellipse_down(self,e):
355         pos = self.getpos(e)
356         self.pos = pos
357         
358     def ellipse_drag(self,e):
359         self.overlay.fill((0,0,0,0))
360         pos = self.getpos(e)
361         r = pygame.Rect(self.pos[0],self.pos[1],pos[0]-self.pos[0],pos[1]-self.pos[1])
362         r.normalize()
363         r.width += 1
364         r.height += 1
365         r.width,r.height = max(2,r.width),max(2,r.height)
366         pygame.draw.ellipse(self.overlay,app.color,r,1)
367         self.repaint()
368     
369     def ellipse_up(self,e):
370         app.archive()
371         self.overlay.fill((0,0,0,0))
372         pos = self.getpos(e)
373         r = pygame.Rect(self.pos[0],self.pos[1],pos[0]-self.pos[0],pos[1]-self.pos[1])
374         r.normalize()
375         r.width += 1
376         r.height += 1
377         r.width,r.height = max(2,r.width),max(2,r.height)
378         pygame.draw.ellipse(app.tile,app.color,r,1)
379         self.repaint()
380         
381     #draw
382     def draw_down(self,e):
383         app.archive()
384         pos = self.getpos(e)
385         app.tile.set_at(pos,app.color)
386         self.pos = pos
387         self.repaint()
388         
389     def draw_drag(self,e):
390         pos = self.getpos(e)
391         pygame.draw.line(app.tile,app.color,self.pos,pos)
392         self.pos = pos
393         self.repaint()
394         
395     def getpos(self,e):
396         x,y = (e.pos[0])*app.tile_w/self.rect.w,(e.pos[1])*app.tile_h/self.rect.h
397         x = min(max(0,x),app.tile_w-1)
398         y = min(max(0,y),app.tile_h-1)
399         return x,y
400     
401     def getpos2(self,e):
402         w = self.rect.w/app.tile_w
403         h = self.rect.h/app.tile_h
404         x,y = (e.pos[0]+w/2)*app.tile_w/self.rect.w,(e.pos[1]+h/2)*app.tile_h/self.rect.h
405         x = min(max(0,x),app.tile_w)
406         y = min(max(0,y),app.tile_h)
407         return x,y
408     
409             
410     
411     #select
412     def select_down(self,e):
413         pos = self.getpos2(e)
414         app.select = Rect(pos[0],pos[1],0,0)
415         self.repaint()
416         
417     def select_drag(self,e):
418         pos = self.getpos2(e)
419         #pos = (e.pos[0]+app.tile_w/2)/app.tile_w,(e.pos[1]+app.tile_h/2)/app.tile_h
420         
421         app.select = Rect(app.select.x,app.select.y,pos[0]-app.select.x,pos[1]-app.select.y)
422         app.select.w = max(0,app.select.w)
423         app.select.h = max(0,app.select.h)
424         
425         #print app.select
426         
427         self.repaint()
428         
429
430         
431     #eraser
432     def eraser_down(self,e):
433         app.archive()
434         pos = self.getpos(e)
435         app.tile.set_at(pos,(0,0,0,0))
436         self.pos = pos
437         self.repaint()
438         
439     def eraser_drag(self,e):
440         pos = self.getpos(e)
441         pygame.draw.line(app.tile,(0,0,0,0),self.pos,pos)
442         self.pos = pos
443         self.repaint()
444         
445
446 def cmd_quit(value):
447     if app.dirty: _dirty(_cmd_quit,value)
448     else: _cmd_quit(value)
449
450 def _cmd_quit(value):
451     app.top.quit()
452
453 def cmd_all(value):
454     app.select = Rect(0,0,app.tile_w,app.tile_h)
455     app.tdraw.repaint()
456
457 def cmd_undo(value):
458     app.undo()
459     
460 def cmd_redo(value):
461     pass
462     
463 def cmd_copy(value):
464     #next version of pygame?
465     #app.clipboard = app.tile.subsurface(app.select).copy()
466     s = app.tile.subsurface(app.select)
467     app.clipboard = pygame.Surface((app.select.w,app.select.h),SWSURFACE,s)
468     app.clipboard.fill((0,0,0,0))
469     app.clipboard.blit(s,(0,0))
470     
471 def cmd_paste(value):
472     if app.clipboard != None:
473         app.archive()
474         app.tile.fill((0,0,0,0),(app.select.x,app.select.y,app.clipboard.get_width(),app.clipboard.get_height()))
475         app.tile.blit(app.clipboard,app.select)
476         app.tdraw.repaint()
477
478 def cmd_cut(value):
479     cmd_copy(value)
480     cmd_delete(value)
481     
482 def cmd_fullscreen(value):
483     pygame.display.toggle_fullscreen()
484     
485 def cmd_delete(value):
486     app.archive()
487     app.tile.fill((0,0,0,0),app.select)
488     app.tdraw.repaint()
489
490 def cmd_fill(value):        
491     app.archive()
492     app.tile.fill(app.color,app.select)
493     app.tdraw.repaint()
494
495 #NOTE: this feature is a temporary HACK, to be replaced by
496 #an ellipse tool in the future
497 def cmd_ellipse(value):
498     app.archive()
499     pygame.draw.ellipse(app.tile,app.color,app.select,1)
500     app.tdraw.repaint()
501         
502 def cmd_rotate(value):
503     a = value
504     app.archive()
505     s = pygame.transform.rotate(app.tile,a)
506     app.tile.fill((0,0,0,0))
507     app.tile.blit(s,(0,0))
508     app.tdraw.repaint()
509     
510 def cmd_flip(value):
511     fh,fv = value
512     app.archive()
513     s = pygame.transform.flip(app.tile,fh,fv)
514     app.tile.fill((0,0,0,0))
515     app.tile.blit(s,(0,0))
516     app.tdraw.repaint()
517
518 def cmd_tpick(value):
519     dx,dy = value
520     off = app.tile.get_offset()
521     app.tpicker.pick((off[0]+dx*app.tile_w,off[1]+dy*app.tile_h))
522     
523 def cmd_mode(value):
524     mode = value
525     app.mode = mode
526
527 def cmd_load(value):
528     if app.dirty: _dirty(_cmd_load,value)
529     else: _cmd_load(value)
530
531
532 def _cmd_load(value):
533     if app.fname == None:
534         ErrorDialog("Load failed","Image is untitled.").open()
535         return
536     raise Restart()
537     
538
539 def cmd_active_save(value):
540     """ we check if we want to save on screen focus...
541     """
542
543     if app.save_activeevent_switch.value:
544         if app.dirty:
545             #"is dirty... saving"
546             return cmd_save(value)
547     else:
548         pass
549         #"is not dirty, not saving"
550
551
552
553
554 def cmd_save(value):
555     if app.fname == None:
556         return cmd_saveas(value)
557     try:
558         # make a temp file... save it there, and then move it in.
559         # so as to avoid race with anything reading it.
560
561         temp_file_name = "tmp_" + app.fname
562         print temp_file_name
563         if have_pil==True:
564             stim = pygame.image.tostring(app.tiles, "RGB")
565             im=Image.fromstring("RGB", (app.tiles.get_width(),app.tiles.get_height()), stim)
566             im.save(temp_file_name)
567         else:
568             pygame.image.save(app.tiles,temp_file_name)
569         #move temp file into place.
570         shutil.move(temp_file_name, app.fname)
571         cfg_to_ini(['tile_w','tile_h','palette'],app.fname)
572         ini_save()
573         app.dirty = 0
574     except Exception, v:
575         ErrorDialog("Save failed.",v).open()
576         return
577     
578 def cmd_saveas(value):
579     dialog = SaveAsDialog()
580     
581     def onchange(value):
582         value.close()
583         vv = value.value
584         fname = vv['fname'].value
585         if len(fname) == 0:
586             ErrorDialog("Save As failed.","File Name too short!").open()
587             return
588         global cfg
589         app.fname = cfg['fname'] = fname
590         return cmd_save(None)
591         
592     dialog.connect(gui.CHANGE,onchange,dialog)
593     dialog.open()
594
595 def cmd_open(value):
596     if app.dirty: _dirty(_cmd_open,value)
597     else: _cmd_open(value)
598
599     
600 def _cmd_open(value):
601     dialog = OpenDialog()
602     
603     def onchange(value):
604         value.close()
605         vv = value.value
606         ok = 0
607         
608         try:        
609             fname,tile_w,tile_h = vv['fname'].value,int(vv['tile_w'].value),int(vv['tile_h'].value)
610             global cfg
611             cfg['fname'] = fname
612             cfg['tile_w'] = tile_w
613             cfg['tile_h'] = tile_h
614             ok = 1
615         except Exception,v:
616             ErrorDialog("Open failed.",v).open()
617             
618         if ok: raise Restart()
619
620     
621     dialog.connect(gui.CHANGE,onchange,dialog)
622     dialog.open()
623
624
625 class Restart(Exception):
626     pass
627 def _dirty(fnc,v):
628     dialog = DirtyDialog()
629     def onchange(value):
630         value.close()
631         return fnc(v)
632     dialog.connect(gui.CHANGE,onchange,dialog)
633     dialog.open()
634     
635 def cmd_new(value):
636     if app.dirty: _dirty(_cmd_new,value)
637     else: _cmd_new(value)
638     
639         
640 def _cmd_new(value):
641     dialog = NewDialog()
642     
643     def onchange(value):
644         value.close()
645         vv = value.value
646         ok = 0
647         try:        
648             width,height,tile_w,tile_h = int(vv['width'].value),int(vv['height'].value),int(vv['tile_w'].value),int(vv['tile_h'].value)
649             global cfg
650             cfg['fname'] = None
651             cfg['width'] = width
652             cfg['height'] = height
653             cfg['tile_w'] = tile_w
654             cfg['tile_h'] = tile_h
655             ok = 1
656         except Exception, v:
657             ErrorDialog("New failed.",v).open()
658         if ok:
659             raise Restart()
660     
661     dialog.connect(gui.CHANGE,onchange,dialog)
662     dialog.open()
663
664
665 menus = [
666     ('File/New',cmd_new,None),
667     ('File/Open',cmd_open,None),
668     ('File/Save',cmd_save,None),
669     ('File/Save As',cmd_saveas,None),
670     ('File/Reload',cmd_load,None),
671     ('File/Quit',cmd_quit,None),
672
673     ('Edit/Undo',cmd_undo,None),
674     #('Edit/Redo',None,None,None),
675     ('Edit/Cut',cmd_cut,None),
676     ('Edit/Copy',cmd_copy,None),
677     ('Edit/Paste',cmd_paste,None),
678     ('Edit/Delete',cmd_delete,None),
679     ('Edit/Fill',cmd_fill,None),
680         ('Edit/Ellipse',cmd_ellipse,None),
681     ('Edit/Select All',cmd_all,None),
682     
683     ('Transform/Rotate 90 CCW',cmd_rotate,90),
684     ('Transform/Rotate 90 CW',cmd_rotate,-90),
685     ('Transform/Flip Horizontal',cmd_flip,(1,0)),
686     ('Transform/Flip Vertical',cmd_flip,(0,1)),
687     ]
688
689 keys = [
690     (K_s,cmd_save,None),
691     (K_d,cmd_load,None),
692
693     (K_a,cmd_all,None),
694     (K_z,cmd_undo,None),
695     #('Edit/Redo',None,None,None),
696     (K_c,cmd_copy,None),
697     (K_v,cmd_paste,None),
698     (K_x,cmd_cut,None),
699     (K_DELETE,cmd_delete,None),
700     (K_f,cmd_fill,None),
701         (K_e,cmd_ellipse,None),
702     
703     (K_LEFTBRACKET,cmd_rotate,90),
704     (K_RIGHTBRACKET,cmd_rotate,-90),
705     (K_COMMA,cmd_flip,(1,0)),
706     (K_PERIOD,cmd_flip,(0,1)),
707     
708     (K_UP,cmd_tpick,(0,-1)),
709     (K_DOWN,cmd_tpick,(0,1)),
710     (K_LEFT,cmd_tpick,(-1,0)),
711     (K_RIGHT,cmd_tpick,(1,0)),
712     
713     (K_F10,cmd_fullscreen,None),
714     ]
715     
716
717 tools = [
718     ('draw','draw'),
719     ('pixel','pixel'),
720     ('line','line'),
721     #('ellipse','ellipse'),
722     ('fill','fill'),
723     ('select','select'),
724     ('eraser','eraser'),
725     ]
726
727
728 def init_ini():
729     ini.read([ini_fname])
730
731 def ini_save():
732     f = open(ini_fname,"wb")
733     ini.write(f)
734     f.close()
735     
736
737 def init_opts():
738     usage = "%prog [tiles.tga] [tile_w] [tile_h]"
739
740     parser = OptionParser(usage)
741     parser.add_option("--sw",dest="screen_w",help="screen width (app)",type='int')
742     parser.add_option("--sh",dest="screen_h",help="screen height (app)",type='int')
743     parser.add_option("--tw",dest="tile_w",help="tile width (image)",type='int')
744     parser.add_option("--th",dest="tile_h",help="tile height (image)",type='int')
745     parser.add_option("--width",dest="width",help="new width (image)",type='int')
746     parser.add_option("--height",dest="height",help="new height (image)",type='int')
747     parser.add_option("-p","--pal",dest="palette",help="filename of palette (image)")
748     parser.add_option("-d","--defaults",dest="defaults",help="set default settings (image)",action="store_true")
749     #parser.add_option("-a","--app",dest="app",help="set application level defaults",action="store_true")
750     
751     (opts,args) = parser.parse_args()
752     
753     if len(args) > 3: parser.error("incorrect number of arguments")
754     
755     #parse arguments
756     if len(args) == 0:
757         opts.fname = "None"
758     elif len(args) == 1:
759         opts.fname = args[0]
760     elif len(args) == 2:
761         opts.fname = "None"
762         try: opts.tile_w,opts.tile_h = int(args[0]),int(args[1])
763         except: parser.error("tile width and height must be integers")
764         if opts.tile_w < 1 or opts.tile_h < 1: parser.error("width and height must be greater than 0")
765     else:
766         try: opts.fname,opts.tile_w,opts.tile_h = args[0],int(args[1]),int(args[2])
767         except: parser.error("tile width and height must be integers")
768         if opts.tile_w < 1 or opts.tile_h < 1: parser.error("width and height must be greater than 0")
769         
770     fname = opts.fname
771     
772     #create all sections
773     for k in [fname,"None","app"]:
774         if not ini.has_section(k):
775             ini.add_section(k)
776     
777     #set app level defaults
778     for k,v in [('screen_w',800),('screen_h',600)]:
779         if not ini.has_option('app',k):
780             ini.set('app',k,str(v))
781             
782     #set app level values
783     for k in ['screen_w','screen_h']:
784         if hasattr(opts,k):
785             v = getattr(opts,k)
786             if v != None: ini.set('app',k,str(v))
787             
788     #set default defaults
789     for k,v in [('width',256),('height',256),('tile_w',32),('tile_h',32),('palette','palette.tga')]:
790         if not ini.has_option('None',k):
791             ini.set('None',k,str(v))
792     
793     #name of keys for normal stuff
794     file_ks = ['width','height','tile_w','tile_h','palette']
795         
796     #set default values
797     if opts.defaults:
798         for k in file_ks:
799             if hasattr(opts,k):
800                 v = getattr(opts,k)
801                 if v != None: ini.set('None',k,str(v))
802     
803     #set fname values
804     for k in file_ks:
805         if hasattr(opts,k):
806             v = getattr(opts,k)
807             if v != None: ini.set(fname,k,str(v))
808     
809     #save the ini
810     ini_save()
811             
812     #convert ini to cfg stuff...
813     ini_to_cfg(['app','None',fname])
814     if fname == 'None': fname = None
815     cfg['fname'] = fname
816     
817             
818 def ini_to_cfg(sections):
819     global cfg
820     ik = ['screen_w','screen_h','tile_w','tile_h','width','height']
821     for s in sections:
822         for k,v in ini.items(s):
823             if k in ik: v = int(v)
824             cfg[k] = v
825 def ini_to_dict(section):
826     cfg = {}
827     ik = ['screen_w','screen_h','tile_w','tile_h','width','height']
828     for s in [section]:
829         for k,v in ini.items(s):
830             if k in ik: v = int(v)
831             cfg[k] = v
832     return cfg
833
834 def cfg_to_ini(ks,section):
835     if not ini.has_section(section): ini.add_section(section)
836     for k in ks:
837         v = cfg[k]
838         ini.set(section,k,str(v))
839         
840         
841 def init_gui():
842     #themes = cfg['theme'].split(",")
843     #gui.theme.load(themes)
844     #gui.theme.load(['default','tools'])
845     global top
846     top = gui.Desktop(theme=gui.Theme(['default','tools']))
847
848     #top = gui.Desktop()
849     #top.theme.load(['default','tools'])
850
851
852     #pass
853     
854 def init_app():
855     global app
856     app = _app()
857
858     #
859     colors_height = 64
860     ss = 8
861         
862     #--- top
863     x,y,h = 0,0,0
864         
865     #menus
866     e = gui.Menus(menus)
867     e.rect.w,e.rect.h = e.resize()
868     app.add(e,x,y)
869     x,h = x+e.rect.w,max(h,e.rect.h)
870     menus_height = e.rect.h
871     
872     #--- row
873     x,y,h = 0,y+h,0
874     
875     #--- vspace
876     y += ss
877     
878     #--- hspace
879     x += ss
880     
881     #tools
882     e = gui.Toolbox(tools,1,0,value='draw') #,"icons48")
883     e.rect.w,e.rect.h = e.resize()
884     def _set_mode(value):
885         cmd_mode(value.value)
886     e.connect(gui.CHANGE,_set_mode,e)
887     app.add(e,x,y)
888
889     
890     #--- vspace
891     y += ss
892
893
894     #--- switchbox for saving.
895     sx, sy = x,y+(max(h,e.rect.h))
896
897     savelabel = gui.Label("Save on")
898     app.add(savelabel, sx,sy)
899     savelabel2 = gui.Label("focus:")
900     app.add(savelabel2, sx,sy+(ss*2))
901
902     #--- vspace
903     y += (ss *5)
904     sy += (ss *5)
905
906     save_activeevent_switch = gui.Switch(False)
907     app.add(save_activeevent_switch, sx,sy)
908     app.save_activeevent_switch = save_activeevent_switch
909
910     x,h = x+e.rect.w,max(h,e.rect.h)
911     toolbox_width = e.rect.w
912
913     #--- hspace
914     x += ss
915     y -= ss*6 #undo what was done above to the y val
916         
917     #tdraw
918     #tdraw-calcs
919     dw = app.screen_w - (toolbox_width+app.tiles.get_width()+ss*4)
920     dh = app.screen_h - (menus_height+colors_height+ss*2)
921     if dw/float(app.tile_w) > dh/float(app.tile_h): dw = dh/float(app.tile_h)*app.tile_w
922     else: dh = dw/float(app.tile_w)*app.tile_h
923     e = app.tdraw = tdraw(dw,dh)
924     app.add(e,x,y)
925     x,h = x+e.rect.w,max(h,e.rect.h)
926     
927     #--- hspace
928     x += ss
929     
930     #tpicker
931     e = app.tpicker = tpicker()
932     e.rect.w,e.rect.h = e.resize()
933     #--- right
934     x = app.screen_w-e.rect.w-ss
935     app.add(e,x,y)
936     h = max(h,e.rect.h)
937
938     #tpreview
939     y = y+e.rect.h
940     e = app.tpreview = tpreview()
941     e.rect.w,e.rect.h = e.resize()
942     app.add(e,x,y)
943     
944     #--- bottom
945     x,y,h = 0,app.screen_h - colors_height,0
946     
947     #cpreview
948     colors_width = toolbox_width + ss * 2
949     e = app.cpreview = cpreview(colors_width,colors_height)
950     e.rect.w,e.rect.h = e.resize()
951     app.add(e,x,y)
952     x,h = x+e.rect.w,max(h,e.rect.h)
953     
954     #cpicker
955     if os.path.isfile(cfg['palette']):
956         pal = pygame.image.load(cfg['palette'])
957     else:
958         #default to EGA / NES palette
959         
960         pw,ph = 16,6
961         pdata = [(0, 0, 0, 255), (0, 0, 170, 255), (0, 170, 0, 255), (0, 170, 170, 255), (170, 0, 0, 255), (170, 0, 170, 255), (170, 85, 0, 255), (170, 170, 170, 255), (85, 85, 85, 255), (85, 85, 255, 255), (85, 255, 85, 255), (85, 255, 255, 255), (255, 85, 85, 255), (255, 85, 255, 255), (255, 255, 85, 255), (255, 255, 255, 255), (0, 0, 0, 255), (0, 0, 0, 255), (0, 0, 0, 255), (0, 0, 0, 255), (0, 0, 0, 255), (0, 0, 0, 255), (0, 0, 0, 255), (0, 0, 0, 255), (0, 0, 0, 255), (0, 0, 0, 255), (0, 0, 0, 255), (0, 0, 0, 255), (0, 0, 0, 255), (0, 0, 0, 255), (0, 0, 0, 255), (0, 0, 0, 255), (255, 255, 255, 255), (173, 243, 255, 255), (223, 214, 255, 255), (255, 190, 255, 255), (255, 176, 255, 255), (255, 177, 237, 255), (255, 191, 185, 255), (255, 217, 145, 255), (237, 246, 128, 255), (185, 255, 138, 255), (145, 255, 173, 255), (128, 255, 223, 255), (138, 255, 255, 255), (197, 197, 197, 255), (0, 0, 0, 255), (0, 0, 0, 255), (255, 255, 255, 255), (129, 200, 255, 255), (179, 171, 255, 255), (231, 146, 255, 255), (255, 132, 244, 255), (255, 133, 194, 255), (255, 148, 141, 255), (244, 173, 101, 255), (194, 202, 84, 255), (141, 227, 94, 255), (101, 240, 129, 255), (84, 240, 179, 255), (94, 225, 231, 255), (120, 120, 120, 255), (0, 0, 0, 255), (0, 0, 0, 255), (192, 192, 192, 255), (57, 128, 200, 255), (108, 99, 217, 255), (160, 74, 207, 255), (200, 61, 172, 255), (217, 61, 122, 255), (207, 76, 70, 255), (172, 102, 30, 255), (122, 130, 13, 255), (70, 155, 23, 255), (30, 169, 57, 255), (13, 168, 108, 255), (23, 153, 160, 255), (61, 61, 61, 255), (0, 0, 0, 255), (0, 0, 0, 255), (128, 128, 128, 255), (16, 87, 159, 255), (67, 58, 176, 255), (119, 34, 166, 255), (159, 20, 131, 255), (176, 20, 81, 255), (166, 35, 29, 255), (131, 61, 0, 255), (81, 89, 0, 255), (29, 114, 0, 255), (0, 128, 16, 255), (0, 127, 67, 255), (0, 112, 119, 255), (0, 0, 0, 255), (0, 0, 0, 255), (0, 0, 0, 255)]
962
963         pal = pygame.Surface((pw,ph),SWSURFACE,32)
964         n=0
965         for py in range(0,ph):
966             for px in range(0,pw):
967                 pal.set_at((px,py),pdata[n])
968                 n+=1
969         
970         
971     e = app.cpicker = cpicker(app.screen_w-colors_width,colors_height,pal)
972     e.rect.w,e.rect.h = e.resize()
973     app.add(e,x,y)
974     x,h = x+e.rect.w,max(h,e.rect.h)
975     
976     pygame.key.set_repeat(500,30)
977     
978     app.screen.fill((255,255,255,255))
979     
980 class NewDialog(gui.Dialog):
981     def __init__(self,**params):
982         title = gui.Label("New...")
983         
984         doc = html.HTML(globals={'gui':gui,'dialog':self},data="""<form id='form'><table>
985         <tr>
986         <td align=center>Image Size
987         <td align=center>Tile Size
988
989         <tr><td colspan='1' align='center' style='padding-right:8px;'><table>
990         <tr><td align=right>Width: <td><input type='text' size='4' value='%(width)s' name='width'>
991         <tr><td align=right>Height: <td><input type='text' size='4' value='%(height)s' name='height'>
992         </table>
993         
994         <td colspan='1' align='center'><table>
995         <tr><td align=right>Width: <td><input type='text' size='4' value='%(tile_w)s' name='tile_w'>
996         <tr><td align=right>Height: <td><input type='text' size='4' value='%(tile_h)s' name='tile_h'>
997         </table>
998         
999         <tr><td colspan=2>Palette: <input type='text' size=20 name='palette' value='%(palette)s'>
1000         
1001         <tr><td>&nbsp;
1002         
1003         <tr><td colspan=2><input type='button' value='Okay' onclick='dialog.send(gui.CHANGE)'> <input type='button' value='Cancel' onclick='dialog.close()'>
1004         
1005         </table>"""%ini_to_dict('None'))
1006         gui.Dialog.__init__(self,title,doc)
1007         
1008         self.value = doc['form']
1009
1010 class SaveAsDialog(gui.Dialog):
1011     def __init__(self,**params):
1012         title = gui.Label("Save As...")
1013         
1014         doc = html.HTML(globals={'gui':gui,'dialog':self},data="""
1015         <form id='form'>
1016         
1017         <table>
1018         
1019         <tr><td colspan=2>File Name: <input type='file' size=20 name='fname' value=''>
1020         
1021         <tr><td>&nbsp;
1022         
1023         <tr><td colspan=2><input type='button' value='Okay' onclick='dialog.send(gui.CHANGE)'> <input type='button' value='Cancel' onclick='dialog.close()'>
1024         
1025         </table>""")
1026         gui.Dialog.__init__(self,title,doc)
1027         
1028         self.value = doc['form']
1029
1030 class OpenDialog(gui.Dialog):
1031     def __init__(self,**params):
1032         title = gui.Label("Open...")
1033         
1034         def load_vals(fname,form):
1035             if not ini.has_section(fname): return
1036             
1037             for k,v in ini.items(fname):
1038                 if k in form:
1039                     form[k].value = v
1040         doc = html.HTML(globals={'load_vals':load_vals,'ini':ini,'gui':gui,'dialog':self},data="""<form id='form'><table>
1041         
1042         <tr><td align=right>File Name:&nbsp;<td  align=left><input type='file' size=20 name='fname' value='' onchange='load_vals(self.value,form)'>
1043         <tr><td align=right>Tile Width:&nbsp;<td align=left><input type='text' size='4' value='%(tile_w)s' name='tile_w'>
1044         <tr><td align=right>Tile Height:&nbsp;<td align=left><input type='text' size='4' value='%(tile_h)s' name='tile_h'>
1045         
1046         <tr><td align=right>Palette:&nbsp;<td align=left><input type='text' size=20 name='palette' value='%(palette)s'>
1047         
1048         <tr><td>&nbsp;
1049         
1050         <tr><td colspan=2><input type='button' value='Okay' onclick='dialog.send(gui.CHANGE)'> <input type='button' value='Cancel' onclick='dialog.close()'>
1051         
1052         </table>"""%ini_to_dict('None'))
1053         gui.Dialog.__init__(self,title,doc)
1054         
1055         self.value = doc['form']
1056
1057 class ErrorDialog(gui.Dialog):
1058     def __init__(self,tt,data,**params):
1059         title = gui.Label("Error: "+tt)
1060         data = str(data)
1061         
1062         doc = html.HTML(globals={'gui':gui,'dialog':self},data="""
1063         <form id='form'>
1064         
1065         <table>
1066         <tr><td><h1>&lt;!&gt;&nbsp;</h1>
1067         <td>"""+data+"""
1068         <tr><td>&nbsp;
1069         <tr><td colspan=2><input type='button' value='Okay' onclick='dialog.send(gui.CHANGE);dialog.close()'>
1070         </table>""")
1071         gui.Dialog.__init__(self,title,doc)
1072         
1073         self.value = doc['form']
1074
1075 class DirtyDialog(gui.Dialog):
1076     def __init__(self,**params):
1077         title = gui.Label("File not yet saved...")
1078         data = "Your file is not yet saved.<br>Are you sure you want to continue?"
1079         
1080         doc = html.HTML(globals={'gui':gui,'dialog':self},data="""
1081         <form id='form'>
1082         
1083         <table>
1084         <tr><td><h1>&lt;!&gt;&nbsp;</h1>
1085         <td>"""+data+"""
1086         <tr><td>&nbsp;
1087         <tr><td colspan=2><input type='button' value='Okay' onclick='dialog.send(gui.CHANGE)'> <input type='button' value='Cancel' onclick='dialog.close()'>
1088         </table>""")
1089         gui.Dialog.__init__(self,title,doc)
1090         
1091         self.value = doc['form']
1092
1093
1094
1095 def run():
1096     #top.connect(gui.QUIT,top.quit,None)
1097     top.connect(gui.QUIT,cmd_quit,None)
1098     top.connect(pygame.ACTIVEEVENT, cmd_active_save,None)
1099     top.init(app,app.screen)
1100     app.top = top
1101     top.run()
1102     
1103
1104 def main():
1105     init_ini()
1106     init_opts()
1107     init_gui()
1108     
1109     restart = 1
1110     while restart:
1111         restart = 0
1112         try:
1113             init_app()
1114             run()
1115         except Restart: restart = 1
1116         
1117
1118         
1119     
1120 main()
1121 # vim: set filetype=python sts=4 sw=4 noet si :

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