2006-08-02 13:59:57 +01:00
|
|
|
#!/usr/bin/python
|
|
|
|
|
|
|
|
#---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
""" Import externals """
|
|
|
|
import wx
|
|
|
|
import time
|
|
|
|
|
|
|
|
#---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
""" Import scyther-gui components """
|
|
|
|
import Icon
|
2006-08-10 12:50:57 +01:00
|
|
|
import Preference
|
2006-08-02 13:59:57 +01:00
|
|
|
|
|
|
|
#---------------------------------------------------------------------------
|
2006-08-10 12:50:57 +01:00
|
|
|
if Preference.usePIL():
|
|
|
|
import Image
|
|
|
|
#---------------------------------------------------------------------------
|
2006-08-02 13:59:57 +01:00
|
|
|
|
|
|
|
class AttackDisplay(wx.ScrolledWindow):
|
2006-08-02 23:07:29 +01:00
|
|
|
def __init__(self, daddy, parent, attack):
|
2006-08-02 13:59:57 +01:00
|
|
|
|
|
|
|
self.win = daddy
|
2006-08-02 23:07:29 +01:00
|
|
|
self.attack = attack
|
2006-08-02 13:59:57 +01:00
|
|
|
|
|
|
|
wx.ScrolledWindow.__init__(self,parent,id=-1)
|
2006-08-09 11:21:30 +01:00
|
|
|
self.SetBackgroundColour('White')
|
2006-08-02 13:59:57 +01:00
|
|
|
|
|
|
|
self.Bind(wx.EVT_SIZE, self.OnSize)
|
|
|
|
self.Image = wx.StaticBitmap(self, -1, wx.EmptyBitmap(1,1))
|
|
|
|
self.box = wx.BoxSizer(wx.VERTICAL)
|
|
|
|
self.box.Add(self.Image,1,wx.ALIGN_CENTER)
|
|
|
|
self.hbox = wx.BoxSizer(wx.HORIZONTAL)
|
|
|
|
self.hbox.Add(self.box,1,wx.ALIGN_CENTER)
|
|
|
|
self.SetSizer(self.hbox)
|
|
|
|
|
2006-08-08 16:14:51 +01:00
|
|
|
self.original = None
|
|
|
|
|
2006-08-04 23:29:51 +01:00
|
|
|
filename = attack.file
|
2006-08-05 00:22:03 +01:00
|
|
|
if attack.filetype == "png":
|
|
|
|
self.original = wx.Image(filename,wx.BITMAP_TYPE_PNG)
|
|
|
|
elif attack.filetype == "ps":
|
|
|
|
# depends on PIL lib
|
|
|
|
self.original = Image.open(filename)
|
|
|
|
else:
|
|
|
|
print "Unknown file type %s." % (self.filetype)
|
|
|
|
|
2006-08-02 13:59:57 +01:00
|
|
|
# TODO self.Bind(wxSizeEvent
|
2006-08-11 16:44:36 +01:00
|
|
|
self.update(True)
|
2006-08-08 16:14:51 +01:00
|
|
|
self.Fit()
|
2006-08-02 13:59:57 +01:00
|
|
|
|
|
|
|
def OnSize(self,event):
|
2006-08-11 16:43:04 +01:00
|
|
|
self.update(False)
|
2006-08-02 13:59:57 +01:00
|
|
|
event.Skip()
|
|
|
|
|
2006-08-11 16:43:04 +01:00
|
|
|
def update(self,force=True):
|
|
|
|
|
|
|
|
if not force:
|
|
|
|
if not self.win.fit:
|
|
|
|
return
|
2006-08-02 13:59:57 +01:00
|
|
|
|
|
|
|
self.SetScrollbars(0,0,0,0,0,0)
|
2006-08-07 15:02:59 +01:00
|
|
|
(sw,sh) = self.GetClientSizeTuple()
|
2006-08-05 00:22:03 +01:00
|
|
|
(W,H) = (sw,sh)
|
2006-08-02 13:59:57 +01:00
|
|
|
|
2006-08-07 13:13:39 +01:00
|
|
|
def makefit(W,H):
|
2006-08-04 23:08:00 +01:00
|
|
|
if self.win.fit:
|
2006-08-07 13:13:39 +01:00
|
|
|
# determine scaling factors for fitting
|
|
|
|
wfactor = float(sw) / W
|
|
|
|
hfactor = float(sh) / H
|
|
|
|
|
|
|
|
# select smallest factor (so it will fit)
|
|
|
|
if hfactor < wfactor:
|
|
|
|
factor = hfactor
|
|
|
|
else:
|
|
|
|
factor = wfactor
|
|
|
|
|
|
|
|
# apply scaling factor
|
|
|
|
W = W * factor
|
|
|
|
H = H * factor
|
|
|
|
return (int(W),int(H))
|
2006-08-05 00:22:03 +01:00
|
|
|
|
|
|
|
if self.attack.filetype == "png":
|
|
|
|
bmp = self.original
|
|
|
|
if not bmp.Ok():
|
2006-08-10 15:42:51 +01:00
|
|
|
bmp = wx.EmptyImage(1,1)
|
2006-08-05 00:22:03 +01:00
|
|
|
else:
|
2006-08-05 00:28:59 +01:00
|
|
|
(W,H) = (bmp.GetWidth(), bmp.GetHeight())
|
2006-08-05 00:22:03 +01:00
|
|
|
if self.win.fit:
|
2006-08-07 13:13:39 +01:00
|
|
|
(W,H) = makefit(W,H)
|
|
|
|
bmp = self.original.Scale(W,H)
|
2006-08-05 00:22:03 +01:00
|
|
|
self.Image.SetBitmap(wx.BitmapFromImage(bmp))
|
2006-08-07 12:54:43 +01:00
|
|
|
|
2006-08-05 00:22:03 +01:00
|
|
|
elif self.attack.filetype == "ps":
|
|
|
|
pil = self.original.copy()
|
2006-08-07 13:13:39 +01:00
|
|
|
(W,H) = pil.size
|
|
|
|
(W,H) = makefit(W,H)
|
2006-08-05 00:22:03 +01:00
|
|
|
# we really only want antialias when it's smaller
|
2006-08-07 13:13:39 +01:00
|
|
|
pil.thumbnail((W,H),Image.ANTIALIAS)
|
2006-08-05 00:22:03 +01:00
|
|
|
|
|
|
|
image = wx.EmptyImage(pil.size[0],pil.size[1])
|
|
|
|
image.SetData(pil.convert('RGB').tostring())
|
|
|
|
self.Image.SetBitmap(image.ConvertToBitmap())
|
|
|
|
else:
|
|
|
|
print "Unknown file type %s." % (self.attack.filetype)
|
2006-08-04 23:08:00 +01:00
|
|
|
|
|
|
|
|
2006-08-02 13:59:57 +01:00
|
|
|
#self.box.SetItemMinSize(self.Image.GetContainingSizer())
|
|
|
|
self.box.Layout()
|
|
|
|
|
|
|
|
# wx.StaticBitmap(self, -1, bmp, (0, 0), (bmp.GetWidth(), bmp.GetHeight()))
|
|
|
|
step = 20
|
2006-08-05 00:22:03 +01:00
|
|
|
xn = int(W / step) + 1
|
|
|
|
yn = int(H / step) + 1
|
2006-08-02 13:59:57 +01:00
|
|
|
self.SetScrollbars(step,step,xn,yn,0,0)
|
|
|
|
|
|
|
|
self.Refresh()
|
|
|
|
|
2006-08-07 15:02:59 +01:00
|
|
|
#---------------------------------------------------------------------------
|
2006-08-02 13:59:57 +01:00
|
|
|
|
|
|
|
class AttackWindow(wx.Frame):
|
|
|
|
def __init__(self,cl):
|
2006-08-11 16:38:25 +01:00
|
|
|
super(AttackWindow, self).__init__(None, size=(400,700))
|
2006-08-09 11:21:30 +01:00
|
|
|
self.SetBackgroundColour('Default')
|
2006-08-02 13:59:57 +01:00
|
|
|
self.claim = cl
|
2006-08-07 15:02:59 +01:00
|
|
|
|
|
|
|
# TODO maybe fitting defaults should come from Preferences.
|
2006-12-12 16:33:21 +00:00
|
|
|
# Now, it is default no even if we have PIL, for performance
|
|
|
|
# reasons.
|
|
|
|
self.fit = False
|
2006-08-07 15:02:59 +01:00
|
|
|
|
2006-08-02 13:59:57 +01:00
|
|
|
self.CreateInteriorWindowComponents()
|
|
|
|
|
|
|
|
Icon.ScytherIcon(self)
|
|
|
|
self.SetTitle()
|
|
|
|
|
|
|
|
def SetTitle(self):
|
|
|
|
|
2006-08-09 13:11:55 +01:00
|
|
|
tstr = self.claim.stateName(len(self.claim.attacks),True)
|
2006-08-02 22:56:14 +01:00
|
|
|
tstr += " for claim %s" % self.claim.id
|
2006-08-02 13:59:57 +01:00
|
|
|
super(AttackWindow, self).SetTitle(tstr)
|
|
|
|
|
|
|
|
def CreateInteriorWindowComponents(self):
|
|
|
|
''' Create "interior" window components. In this case it is the
|
|
|
|
attack picture. '''
|
|
|
|
|
2006-08-07 15:02:59 +01:00
|
|
|
sizer = wx.BoxSizer(wx.VERTICAL)
|
2006-08-10 15:58:08 +01:00
|
|
|
|
|
|
|
# Make zoom buttons
|
|
|
|
if Preference.usePIL():
|
|
|
|
buttons = wx.BoxSizer(wx.HORIZONTAL)
|
2006-08-11 10:41:12 +01:00
|
|
|
bt = wx.ToggleButton(self,-1,"Fit to window")
|
|
|
|
bt.SetValue(self.fit)
|
2006-08-10 15:58:08 +01:00
|
|
|
buttons.Add(bt,0)
|
2006-08-11 10:41:12 +01:00
|
|
|
self.Bind(wx.EVT_TOGGLEBUTTON, self.OnFit, bt)
|
2006-08-10 15:58:08 +01:00
|
|
|
sizer.Add(buttons, 0, wx.ALIGN_LEFT)
|
2006-08-07 15:02:59 +01:00
|
|
|
|
|
|
|
# Add attacks (possible with tabs)
|
2006-08-02 13:59:57 +01:00
|
|
|
self.displays=[]
|
2006-08-03 14:40:39 +01:00
|
|
|
attacks = self.claim.attacks
|
|
|
|
n = len(attacks)
|
|
|
|
if n <= 1:
|
2006-08-02 13:59:57 +01:00
|
|
|
# Just a single window
|
2006-08-07 15:02:59 +01:00
|
|
|
dp = AttackDisplay(self, self, attacks[0])
|
|
|
|
self.displays.append(dp)
|
2006-08-02 13:59:57 +01:00
|
|
|
else:
|
|
|
|
# Multiple tabs
|
2006-08-07 15:02:59 +01:00
|
|
|
dp = wx.Notebook(self,-1)
|
2006-08-03 14:40:39 +01:00
|
|
|
for i in range(0,n):
|
2006-08-07 15:02:59 +01:00
|
|
|
disp = AttackDisplay(self,dp,attacks[i])
|
2006-08-09 13:11:55 +01:00
|
|
|
classname = "%s %i" % (self.claim.stateName(1,True),(i+1))
|
2006-08-07 15:02:59 +01:00
|
|
|
dp.AddPage(disp, classname)
|
2006-08-02 13:59:57 +01:00
|
|
|
self.displays.append(disp)
|
|
|
|
|
2006-08-07 15:02:59 +01:00
|
|
|
sizer.Add(dp, 1, wx.EXPAND,1)
|
2006-08-02 13:59:57 +01:00
|
|
|
|
2006-08-07 15:02:59 +01:00
|
|
|
self.SetSizer(sizer)
|
2006-08-02 13:59:57 +01:00
|
|
|
|
2006-08-11 16:43:04 +01:00
|
|
|
def update(self,force=False):
|
2006-08-02 13:59:57 +01:00
|
|
|
for t in self.displays:
|
2006-08-11 16:43:04 +01:00
|
|
|
t.update(force)
|
2006-08-02 13:59:57 +01:00
|
|
|
|
|
|
|
def OnFit(self,event):
|
|
|
|
|
|
|
|
if self.fit:
|
|
|
|
self.fit = False
|
|
|
|
else:
|
|
|
|
self.fit = True
|
2006-08-11 16:43:04 +01:00
|
|
|
self.update(True)
|
2006-08-02 13:59:57 +01:00
|
|
|
|
|
|
|
def OnRealSize(self):
|
|
|
|
|
|
|
|
self.fit = False
|
2006-08-11 16:43:04 +01:00
|
|
|
self.update(True)
|
2006-08-02 13:59:57 +01:00
|
|
|
|
2006-08-07 15:02:59 +01:00
|
|
|
def OnSize(self):
|
|
|
|
self.Refresh()
|
|
|
|
|
|
|
|
def OnZoom100(self,evt):
|
|
|
|
self.fit = False
|
2006-08-11 16:43:04 +01:00
|
|
|
self.update(True)
|
2006-08-11 10:41:12 +01:00
|
|
|
self.Refresh()
|
2006-08-07 15:02:59 +01:00
|
|
|
|
|
|
|
def OnZoomFit(self,evt):
|
|
|
|
self.fit = True
|
2006-08-11 16:43:04 +01:00
|
|
|
self.update(True)
|
2006-08-11 10:41:12 +01:00
|
|
|
self.Refresh()
|
|
|
|
|
2006-08-07 15:02:59 +01:00
|
|
|
|
|
|
|
|