__author__ = "Aaron Straup Cope"
__url__ = "http://www.mirrorproject.com/widget/"
__version__ = "1.0"
__cvsversion__ = "$Revision: 1.2 $"
__date__ = "$Date: 2004/04/19 02:39:20 $"
__copyright__ = "%s\n%s\n%s\n\n%s\n%s" % \
("This application is licensed under the",
"Creative Commons Attribution-NonCommercial License",
"http://creativecommons.org/licenses/by-nc/1.0/",
"Individual photographs are copyright The Mirror Project",
"and their respective photographers, all rights reserved.")
__license__ = "This application is licensed under the Creative \
Commons Attribution-NonCommercial License. To view a copy of this \
license, visit http://creativecommons.org/licenses/by-nc/1.0/ or send \
a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, \
California 94305, USA. Individual photographs are copyright The Mirror \
Project and their respective photographers, all rights reserved."
from wxPython.wx import *
from cStringIO import StringIO
from time import sleep
from xmlrpclib import Server
from os import name
# this is an unfortunate hack to
# deal with some questionable design
# decisions on the server side...
from urllib import unquote_plus
URL_MIRRORPROJECT = "http://www.mirrorproject.com/xml/"
SECONDS_DELAY = 30
SECONDS_SLEEP = 0.01
COUNTER_DELAY = int(1/SECONDS_SLEEP) * SECONDS_DELAY
# Insert hand-waving about internationalization
# here. Patches welcome...
TITLE_MP = "The Mirror Project"
TITLE_APP = "Random Image Widget"
TITLE_ABOUT = "About"
TITLE_INFO = "Image Info"
MENUBAR_FILE = "&File"
MENUBAR_TOOLS = "&Tools"
MENUBAR_HELP = "&Help"
MENU_ABOUT = "&About"
MENU_PAUSE = "&Pause"
MENU_RESUME = "&Resume"
MENU_INFO = "Image &Info"
MENU_QUIT = "&Quit"
DESCRIBE_PAUSE = "Pause"
DESCRIBE_RESUME = "Resume"
DESCRIBE_INFO = "Info"
DESCRIBE_ABOUT = "More information about this program"
DESCRIBE_QUIT = "Quit the program"
MSG_PAUSED = "paused, press Ctrl-R to resume"
MSG_POLLING = "asking for a new image"
MSG_PROCESSING = ""
ERR_POLLING = "failed to get image from server"
ERR_STRINGIFY = "failed to read image from server"
ERR_STREAMIFY = "failed to munge image"
ERR_DISPLAY = "failed to set image"
ERR_IMAGEINFO = "no image data"
DIALOG_ABOUT = "%s\n%s\nversion %s\n\n%s" % \
(TITLE_MP,
TITLE_APP,
__version__,
__copyright__)
# These need better names...
STATUSTEXT = 0.8
BORDER = 4
#
ID_APP = wxNewId()
ID_PAUSE = wxNewId()
ID_RESUME = wxNewId()
ID_INFO = wxNewId()
ID_ABOUT = wxNewId()
ID_EXIT = wxNewId()
class mpApp(wxApp):
def OnInit(self):
wxInitAllImageHandlers()
self.Server = Server(URL_MIRRORPROJECT)
frame = mpFrame(NULL, ID_APP, TITLE_MP)
frame.Show(true)
self.SetTopWindow(frame)
frame.Panel.SetFocus()
return true
def MainLoop(self):
frame = self.GetTopWindow()
while frame and frame.Panel :
if frame.Paused == true:
wxSafeYield(frame,true)
else:
frame.DisplayRandom(self.Server)
for i in range(COUNTER_DELAY):
sleep(SECONDS_SLEEP)
if frame and frame.Panel:
if frame.Paused == true:
break
else:
wxYield()
else:
break
class mpFrame(wxFrame):
def __init__(self, parent, ID, title):
wxFrame.__init__(self, parent, ID, title,
wxDefaultPosition,
wxSize(300,300))
self.CreateStatusBar()
FileMenu = wxMenu()
FileMenu.Append(ID_PAUSE,
MENU_PAUSE,
DESCRIBE_PAUSE)
FileMenu.Append(ID_RESUME,
MENU_RESUME,
DESCRIBE_RESUME)
FileMenu.AppendSeparator()
FileMenu.Append(ID_EXIT,
MENU_QUIT,
DESCRIBE_QUIT)
FileMenu.Enable(ID_RESUME,false)
ToolsMenu = wxMenu()
ToolsMenu.Append(ID_INFO,
MENU_INFO,
DESCRIBE_INFO)
HelpMenu = wxMenu()
HelpMenu.Append(ID_ABOUT,
MENU_ABOUT,
DESCRIBE_ABOUT)
menuBar = wxMenuBar()
menuBar.Append(FileMenu, MENUBAR_FILE);
menuBar.Append(ToolsMenu, MENUBAR_TOOLS);
menuBar.Append(HelpMenu, MENUBAR_HELP);
self.SetMenuBar(menuBar)
self.Panel = mpPanel(self, -1)
self.Image = None
self.Caption = None
self.Data = {}
self.Paused = false
self.Die = false
EVT_MENU(self, ID_PAUSE, self.Pause)
EVT_MENU(self, ID_RESUME, self.Resume)
EVT_MENU(self, ID_INFO, self.Info)
EVT_MENU(self, ID_ABOUT, self.About)
EVT_MENU(self, ID_EXIT, self.Quit)
EVT_CLOSE(self,self.Quit)
# Doesn't appear to work under
# py-wxPython (FreeBSD)
EVT_MENU_CLOSE(self,self.SetCaption)
EVT_KEY_DOWN(self.Panel, self.KeyDown)
def Yield(self):
# This causes Windows to hang
# FreeBSD hangs without it...
if name == "nt":
pass
else:
wxSafeYield(self,true)
def ReportError(self,msg):
if msg:
self.SetStatusText("[%s]" % self.PrepareStatusText(msg))
else:
self.SetStatusText("")
self.Yield()
def ReportActivity(self,msg):
if msg:
self.SetStatusText("[%s]" % self.PrepareStatusText(msg))
else:
self.SetStatusText("")
self.Yield()
def Pause(self,event):
if self.Paused == true:
return true
self.Paused = true
self.ReportActivity(MSG_PAUSED)
# http://wiki.wxpython.org/index.cgi/ \
# wxPython_20Platform_20Inconsistencies
menu = self.GetMenuBar().FindItemById(-1).GetMenu()
menu.Enable(ID_PAUSE,false)
menu.Enable(ID_RESUME,true)
def Resume(self,event):
if self.Paused == false:
return true
self.Paused = false
# http://wiki.wxpython.org/index.cgi/ \
# wxPython_20Platform_20Inconsistencies
menu = self.GetMenuBar().FindItemById(-1).GetMenu()
menu.Enable(ID_PAUSE,true)
menu.Enable(ID_RESUME,false)
def Info(self,event):
if len(self.Data) == 0:
msg = ERR_IMAGEINFO
else:
msg = "%s\n" % (self.Data["who"])
if self.Data["what"]:
msg = "%s \"%s\"\n" % (msg,self.Data["what"])
msg = "%s\n" % (msg)
# god help me, there
# *must* be a better
# way...
if self.Data["where"]:
msg = "%s%s" % (msg,self.Data["where"])
if self.Data["when"]:
if self.Data["where"]:
msg = "%s, %s" % (msg,self.Data["when"])
else:
msg = "%s%s" % (msg,self.Data["when"])
dlg = wxMessageDialog(self,
msg,
TITLE_INFO,
wxOK | wxICON_INFORMATION)
dlg.ShowModal()
dlg.Destroy()
def KeyDown(self,event):
if event.ControlDown():
keycode = event.GetKeyCode()
else:
event.Skip()
return true
if keycode <= 256:
keyname = chr(keycode)
else:
event.Skip()
return true
if keyname == "A":
self.About(event)
elif keyname == "I":
self.Info(event)
elif keyname == "P":
self.Pause(event)
elif keyname == "R":
self.Resume(event)
elif keyname == "Q":
self.Quit(event)
else:
event.Skip()
return true
def About(self, event):
dlg = wxMessageDialog(self,
DIALOG_ABOUT,
TITLE_ABOUT,
wxOK | wxICON_INFORMATION)
dlg.ShowModal()
dlg.Destroy()
def Quit(self, event):
# this is required by "nt"
# and, I think, "os x"
self.Panel.Destroy()
self.Destroy()
def DisplayRandom(self,server):
self.ReportActivity(MSG_POLLING)
try:
resp = server.mirror.RandomImage()
except:
self.ReportError(ERR_POLLING)
return false
self.ReportActivity(MSG_PROCESSING)
try:
data = StringIO(resp["image"].data)
except:
self.ReportError(ERR_STRINGIFY)
return false
try:
image = wxImageFromStream(data)
except:
self.ReportError(ERR_STREAMIFY)
return false
try:
self.Panel.Display(image)
except:
self.ReportError(ERR_DISPLAY)
return false
self.SetWindow(image)
# the unquote_plus stuff is a hack;
# see notes in import block above
self.Data["who"] = unquote_plus(resp["who"])
self.Data["what"] = unquote_plus(resp["what"])
self.Data["where"] = unquote_plus(resp["where"])
self.Data["when"] = unquote_plus(resp["when"])
if self.Data["what"]:
caption = "%s, %s" % (self.Data["who"],self.Data["what"])
else:
caption = self.Data["who"]
#
caption = self.PrepareStatusText(caption,
int(image.GetWidth() * STATUSTEXT))
#
self.Caption = caption
self.SetCaption()
return true
def SetCaption(self,event=None):
if self.Caption:
self.SetStatusText(self.Caption)
else:
self.SetStatusText("")
def PrepareStatusText(self,txt,max=0):
# Okay, now we have to make sure that the
# text will fit in the status bar
(txt_x,txt_y) = self.GetTextExtent(txt)
if max == 0:
max = int(self.GetSize()[0] * STATUSTEXT)
if txt_x > max:
while txt_x > max:
# please make the python keeners
# shut the fuck up about how great
# their language is. my kingdom for
# a substring function...
txt = txt[0:len(txt) - 1]
# just in case
if len(txt) == 1:
txt = ""
break
(txt_x,txt_y) = self.GetTextExtent(txt)
txt = "%s..." % txt
#
return txt
def SetWindow(self,image):
scr_x = wxSystemSettings_GetMetric(wxSYS_SCREEN_X)
scr_y = wxSystemSettings_GetMetric(wxSYS_SCREEN_Y)
(sb_x,sb_y) = self.GetStatusBar().GetSize()
(mb_x,mb_y) = self.GetMenuBar().GetSize()
(pos_x,pos_y) = self.GetPosition()
# must find a way to measure
# the width of the various
# windowing border elements
count_border_offset = 2.25
width_border_side = 3
if name == "nt":
count_border_offset *= 2
width_border_side *= 2.75
# windows returns something
# cracked like (999334,0)
# this is a bug...
mb_y = 25
#
img_x = image.GetWidth()
img_x += (BORDER * count_border_offset)
img_y = image.GetHeight()
img_y += (BORDER * width_border_side)
# no comment
if name == "nt":
img_x -= 1
#
win_x = int(img_x)
win_y = int(img_y + sb_y + mb_y)
new_x = pos_x
new_y = pos_y
move = false
#
if (pos_x + win_x) > scr_x:
new_x = scr_x - (win_x + (BORDER * count_border_offset))
move = true
if (pos_y + win_y) > scr_y:
new_y = scr_y - (win_y + (BORDER * count_border_offset))
move = true
if move:
self.SetPosition((new_x,new_y))
#
self.SetSize(wxSize(win_x,win_y))
class mpPanel(wxPanel):
def __init__(self, parent, id):
wxPanel.__init__(self, parent, id)
self.Image = None
EVT_PAINT(self, self.OnPaint)
def Display(self, image):
self.Image = image
self.Refresh(True)
def OnPaint(self, evt):
if self.Image:
img_x = self.Image.GetWidth()
img_y = self.Image.GetHeight()
dc = wxPaintDC(self)
dc.SetBrush(wxBrush("#000000"))
# 3/7 should be computed somewhere...
dc.DrawRectangle(0,3,
img_x + (BORDER * 2),
img_y + (BORDER * 2))
dc.DrawBitmap(self.Image.ConvertToBitmap(), BORDER,7)
# Make it so!
app = mpApp(0)
app.MainLoop()
syntax highlighted by Code2HTML, v. 0.9.1