PyXR

c:\projects\bitpim\src \ aggregatedisplay.py



0001 ### BITPIM
0002 ###
0003 ### Copyright (C) 2004 Roger Binns <rogerb@rogerbinns.com>
0004 ###
0005 ### This program is free software; you can redistribute it and/or modify
0006 ### it under the terms of the BitPim license as detailed in the LICENSE file.
0007 ###
0008 ### $Id: aggregatedisplay.py 3298 2006-05-28 03:10:52Z skyjunky $
0009 
0010 "Displays a number of sections each with a number of items"
0011 
0012 import wx
0013 import sys
0014 import guihelper
0015 
0016 ActivateEvent, EVT_ACTIVATE = wx.lib.newevent.NewCommandEvent()
0017 
0018 class BufferedPaintDC(wx.BufferedPaintDC):
0019     def __init__(self, *arg, **karg):
0020         super(BufferedPaintDC, self).__init__(*arg, **karg)
0021         self.view_start=(0,0)
0022         self.pos=(0,0)
0023 
0024 class Display(wx.ScrolledWindow):
0025     "This is the view"
0026 
0027     class HitTestResult:
0028         "Where a particular point corresponds to"
0029         IN_BACKGROUND=0
0030         IN_SECTION=1
0031         IN_ITEM=2
0032 
0033         def __init__(self, **kwds):
0034             self.__dict__.update({
0035                 'location': self.IN_BACKGROUND,
0036                 'sectionnum': None,
0037                 'section': None,
0038                 'sectionx': None,
0039                 'sectiony': None,
0040                 'itemnum': None,
0041                 'item': None,
0042                 'itemx': None,
0043                 'itemy': None,
0044                 })
0045             self.__dict__.update(kwds)
0046 
0047         def __str__(self):
0048             res="<HitTestResult "
0049             if self.location==self.IN_BACKGROUND:
0050                 res+="IN_BACKGROUND>"
0051             elif self.location==self.IN_SECTION:
0052                 res+="IN_SECTION, sectionnum=%d, section=%s, sectionx=%d, sectiony=%d>" % \
0053                       (self.sectionnum, self.section, self.sectionx, self.sectiony)
0054             elif self.location==self.IN_ITEM:
0055                 res+="IN_ITEM, sectionnum=%d, section=%s, itemnum=%d, item=%s, itemx=%d, itemy=%d>" % \
0056                       (self.sectionnum, self.section, self.itemnum, self.item, self.itemx, self.itemy)
0057             else:
0058                 assert False, "bad location"
0059                 res+="ERROR>"
0060             return res
0061 
0062 
0063     # See the long note in OnPaint before touching this code
0064 
0065     VSCROLLPIXELS=3 # how many pixels we scroll by
0066 
0067     ITEMPADDING=5   # how many pixels we pad items by
0068     
0069     def __init__(self, parent, datasource, watermark=None):
0070         wx.ScrolledWindow.__init__(self, parent, id=wx.NewId(), style=wx.FULL_REPAINT_ON_RESIZE|wx.SUNKEN_BORDER)
0071         self.exceptioncount=0
0072         self.EnableScrolling(False, False)
0073         self.datasource=datasource
0074         self._bufbmp=None
0075         self.active_section=None
0076         self._w, self._h=-1,-1
0077         self.vheight, self.maxheight=self._h,self._h
0078         self.sections=[]
0079         self.sectionheights=[]
0080         self._scrollbarwidth=wx.SystemSettings_GetMetric(wx.SYS_VSCROLL_X)
0081         wx.EVT_SIZE(self, self.OnSize)
0082         wx.EVT_PAINT(self, self.OnPaint)
0083         wx.EVT_ERASE_BACKGROUND(self, self.OnEraseBackground)
0084         wx.EVT_LEFT_DOWN(self, self.OnLeftDown)
0085         wx.EVT_LEFT_DCLICK(self, self.OnLeftDClick)
0086         wx.EVT_RIGHT_DOWN(self, self.OnRightDown)
0087         if watermark is not None:
0088             wx.EVT_SCROLLWIN(self, self.OnScroll)
0089 
0090         bgcolour=wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)
0091         if guihelper.IsMac():
0092             bgcolour=wx.WHITE
0093         self.bgbrush=wx.TheBrushList.FindOrCreateBrush(bgcolour, wx.SOLID)
0094         if watermark:
0095             self.watermark=guihelper.getbitmap(watermark)
0096         else:
0097             self.watermark=None
0098         self.UpdateItems()
0099 
0100     def OnScroll(self, evt):
0101         self.Refresh(False)
0102         evt.Skip()
0103 
0104     def OnSize(self, evt):
0105         self.Refresh(False)
0106 
0107     def OnEraseBackground(self, _):
0108         pass
0109 
0110     def SetActiveSection(self, section):
0111         if self.active_section!=section:
0112             self.active_section=section
0113             self.ReLayout()
0114             self.Refresh(False)
0115 
0116     def OnPaint(self, event):
0117         # Getting this drawing right involved hours of fighting wxPython/wxWidgets.
0118         # Those hours of sweating and cursing reveal the following:
0119         #
0120         # - The bufferedpaintdc only allocates a bitmap large enough to cover the
0121         #   viewable window size.  That is used irrespective of the scroll position
0122         #   which means you get garbage for any part of your window beyond the
0123         #   initial physical viewable size
0124         #
0125         # - The bufferedpaintdc must have its origin reset back to zero by the time
0126         #   its destructor is called otherwise it won't draw in the right place
0127         #
0128         # - The various other calls are very carefully placed (eg size handler, ReLayout
0129         #   being a callafter etc).  Otherwise really silly things happen due to the
0130         #   order that things get displayed in, scrollbars adjustments causing your
0131         #   window to get cropped behind the scenes and various other annoyances, setting
0132         #   scrollbars changing size etc
0133         #
0134         # - The ReLayout happens very frequently.  It may be possible to optimise out
0135         #   some calls to it.  Tread very carefully and test on multiple platforms.
0136         #
0137         # - wx sometimes misbehaves if the window height isn't set to an exact multiple of the
0138         #   VSCROLLPIXELS
0139 
0140         sz=self.GetClientSize()
0141         _relayout=False
0142         if sz != (self._w,self._h):
0143             self._w,self._h=sz
0144             _relayout=True
0145             self.ReLayout()
0146             # relayout may change size (scrollbar appearing/going away) so repeat in that case
0147             if self.GetClientSize()!=sz:
0148                 return self.OnPaint(event)
0149 
0150         if self._bufbmp is None or self._bufbmp.GetWidth()<self._w or self._bufbmp.GetHeight()<self.maxheight:
0151             self._bufbmp=wx.EmptyBitmap((self._w+64)&~8, (self.maxheight+64)&~8)
0152         dc=BufferedPaintDC(self, self._bufbmp, style=wx.BUFFER_VIRTUAL_AREA)
0153         try:
0154             self.DoPaint(dc, _relayout)
0155         except:
0156             # only raise one exception - swallow any more
0157             self.exceptioncount+=1
0158             if self.exceptioncount<=1:
0159                 print "raise"
0160                 raise
0161 
0162     def DoPaint(self, dc, relayout=False):
0163         # we redraw everything that is in the visible area of the screen
0164         vs=self.GetViewStart()
0165         dc.view_start=(vs[0], vs[1]*self.VSCROLLPIXELS)
0166         origin=dc.view_start[1]
0167         firstvisible=origin
0168         lastvisible=origin+self._h
0169 
0170         # clear background
0171         dc.SetBackground(self.bgbrush)
0172         # only clear area you can see
0173         dc.SetClippingRegion(0, firstvisible, self._w+1, lastvisible-firstvisible+1)
0174         dc.Clear()
0175         # draw watermark
0176         if self.watermark:
0177             # place in the middle:
0178             # dc.DrawBitmap(self.watermark, self._w/2-self.watermark.GetWidth()/2, origin+self._h/2-self.watermark.GetHeight()/2, True)
0179             # place in bottom right:
0180             dc.DrawBitmap(self.watermark, self._w-self.watermark.GetWidth(), origin+self._h-self.watermark.GetHeight(), True)
0181 
0182         # draw active section
0183         cury=0
0184         for i, section in enumerate(self.sections):
0185             if self.active_section!=None and section.label!=self.active_section:
0186                 continue
0187             if relayout or _isvisible(cury, cury+self.sectionheights[i], firstvisible, lastvisible):
0188                 dc.SetDeviceOrigin(0, cury )
0189                 section.Draw(dc, self._w)
0190             cury+=self.sectionheights[i]
0191             extrawidth=(self._w-6)-(self.itemsize[i][0]+self.ITEMPADDING)*self.itemsperrow[i]
0192             extrawidth/=self.itemsperrow[i]
0193             if extrawidth<0: extrawidth=0
0194             # now draw items in this section
0195             num=0
0196             while num<len(self.items[i]):
0197                 x=(num%self.itemsperrow[i])
0198                 y=(num/self.itemsperrow[i])
0199                 posy=cury+y*(self.itemsize[i][1]+self.ITEMPADDING)
0200                 # skip the entire row if it isn't visible
0201                 if not relayout and \
0202                    x==0 and \
0203                    not _isvisible(posy, posy+self.itemsize[i][1], firstvisible, lastvisible):
0204                     num+=self.itemsperrow[i]
0205                     continue
0206                 item=self.items[i][num]
0207                 dc.pos=(3+x*(self.itemsize[i][0]+self.ITEMPADDING+extrawidth), posy)
0208                 dc.SetDeviceOrigin(*dc.pos)
0209                 dc.ResetBoundingBox()
0210                 bb=item.Draw(dc, self.itemsize[i][0]+extrawidth, self.itemsize[i][1], self.selected[i][num])
0211                 if bb is None:
0212                     bb=dc.MinX(), dc.MinY(), dc.MaxX(), dc.MaxY()
0213                 assert len(bb)==4
0214                 try:
0215                     assert bb[0]>=0 and bb[0]<self.itemsize[i][0]+extrawidth
0216                     assert bb[1]>=0 and bb[1]<self.itemsize[i][1]
0217                     assert bb[2]>=bb[0] and bb[2]<=self.itemsize[i][0]+extrawidth
0218                     assert bb[3]>=bb[1] and bb[3]<=self.itemsize[i][1]
0219                 except:
0220                     print "bb is",bb
0221                     print "should be within",(self.itemsize[i][0]+extrawidth,self.itemsize[i][1])
0222         
0223                 self.boundingboxes[i][num]=bb
0224                 num+=1
0225             cury+=(len(self.items[i])+self.itemsperrow[i]-1)/self.itemsperrow[i]*(self.itemsize[i][1]+self.ITEMPADDING)
0226                     
0227         # must do this or the world ends ...
0228         dc.SetDeviceOrigin(0,0)
0229 
0230     def OnLeftDown(self, evt):
0231         self.SetFocus()
0232         actualx,actualy=self.CalcUnscrolledPosition(evt.GetX(), evt.GetY())
0233         res=self.HitTest(actualx, actualy)
0234         if res.item is None:
0235             if len(self.GetSelection()):
0236                 self.ClearSelection()
0237             return
0238         # if neither control or shift is down then clear selection and add this item
0239         if not evt.ControlDown() and not evt.ShiftDown():
0240             self.SetSelectedByNumber(res.sectionnum, res.itemnum, False)
0241             return
0242         # if control and shift are down then treat as just shift
0243         if evt.ShiftDown():
0244             self.SetSelectedByNumber(res.sectionnum, res.itemnum, True)
0245             return
0246         assert evt.ControlDown()
0247         # we toggle the item
0248         self.selected[res.sectionnum][res.itemnum]=not self.selected[res.sectionnum][res.itemnum]
0249         self.Refresh(False)
0250 
0251     def OnLeftDClick(self, evt):
0252         actualx,actualy=self.CalcUnscrolledPosition(evt.GetX(), evt.GetY())
0253         res=self.HitTest(actualx, actualy)
0254         if res.item is None:
0255             if len(self.GetSelection()):
0256                 self.ClearSelection()
0257             return
0258         self.SetSelectedByNumber(res.sectionnum, res.itemnum,  False) # make this the only selected item
0259         wx.PostEvent(self, ActivateEvent(self.GetId(), item=res.item))
0260 
0261     def OnRightDown(self, evt):
0262         self.SetFocus()
0263         actualx,actualy=self.CalcUnscrolledPosition(evt.GetX(), evt.GetY())
0264         res=self.HitTest(actualx, actualy)
0265         if res.item is None:
0266             self.ClearSelection()
0267         else:
0268             # if item is not in selection then change selection to item
0269             if not self.IsSelectedByNum(res.sectionnum, res.itemnum):
0270                 self.SetSelectedByNumber(res.sectionnum, res.itemnum)
0271 
0272     def GetAllItems(self):
0273         """Returns all items
0274 
0275         The return value is a list.  Each item in the list is a tuple of
0276         (sectionnumber, sectionobject, itemnumber, itemobject)"""
0277         res=[]
0278         for s,section in enumerate(self.sections):
0279             if self.active_section!=None and section.label!=self.active_section:
0280                 continue
0281             for i,item in enumerate(self.items[s]):
0282                 res.append( (s,section,i,item) )
0283         return res
0284 
0285     def IsSelectedByNum(self, sectionnum, itemnum):
0286         "Returns if the itemnum from sectionnum is selected"
0287         return self.selected[sectionnum][itemnum]
0288 
0289     def IsSelectedByObject(self, itemobj):
0290         "Returns if the itemobject is selected"
0291         for s,section in enumerate(self.sections):
0292             if self.active_section!=None and section.label!=self.active_section:
0293                 continue
0294             for i,item in enumerate(self.items[s]):
0295                 if item is itemobj:
0296                     return self.IsSelectedByNum(s,i)
0297         raise ValueError("no such item "+itemobj)
0298 
0299     def GetSelection(self):
0300         """Returns the selected items
0301 
0302         The return value is a list.  Each item in the list is a tuple of
0303         (sectionnumber, sectionobject, itemnumber, itemobject)"""
0304         res=[]
0305         for s,section in enumerate(self.sections):
0306             if self.active_section!=None and section.label!=self.active_section:
0307                 continue
0308             for i,item in enumerate(self.items[s]):
0309                 if self.selected[s][i]:
0310                     res.append( (s,section,i,item) )
0311         return res
0312 
0313     def ClearSelection(self):
0314         self.selected=[ [False]*len(items) for items in self.items]
0315         self.Refresh(False)
0316 
0317     def SelectAll(self):
0318         self.selected=[ [True]*len(items) for items in self.items]
0319         self.Refresh(False)
0320 
0321     def SetSelectedByNumber(self, sectionnum, itemnum, add=False):
0322         if not add:
0323             self.ClearSelection()
0324         self.selected[sectionnum][itemnum]=True
0325         self.Refresh(False)
0326 
0327     def SetSelectedByObject(self, itemobj, add=False):
0328         if not add:
0329             self.ClearSelection()
0330         for s,section in enumerate(self.sections):
0331             if self.active_section!=None and section.label!=self.active_section:
0332                 continue
0333             for i,item in enumerate(self.items[s]):
0334                 if item is itemobj:
0335                     self.selected[s][i]=True
0336                     self.Refresh(False)
0337                     return
0338         raise ValueError("no such item "+itemobj)
0339         
0340                     
0341     def HitTest(self, pointx, pointy):
0342         # work out which item this corresponds to
0343         origin=self.GetViewStart()[1]*self.VSCROLLPIXELS # used later
0344         cury=0
0345         for i, section in enumerate(self.sections):
0346             if self.active_section!=None and section.label!=self.active_section:
0347                 continue
0348             if cury<=pointy<=cury+self.sectionheights[i]:
0349                 # in the section
0350                 return self.HitTestResult(location=self.HitTestResult.IN_SECTION,
0351                                           sectionnum=i, section=section,
0352                                           sectionx=pointx, sectiony=pointy-cury)
0353             if cury>pointy:
0354                 return self.HitTestResult()
0355             cury+=self.sectionheights[i]
0356             extrawidth=(self._w-6)-(self.itemsize[i][0]+self.ITEMPADDING)*self.itemsperrow[i]
0357             extrawidth/=self.itemsperrow[i]
0358             if extrawidth<0: extrawidth=0
0359             # now find items in this section
0360             num=0
0361             while num<len(self.items[i]):
0362                 x=(num%self.itemsperrow[i])
0363                 y=(num/self.itemsperrow[i])
0364                 posy=cury+y*(self.itemsize[i][1]+self.ITEMPADDING)
0365                 # skip the entire row if it isn't in range
0366                 if x==0 and not posy<=pointy<=posy+self.itemsize[i][1]:
0367                     num+=self.itemsperrow[i]
0368                     continue
0369                 item=self.items[i][num]
0370                 bbox=self.boundingboxes[i][num]
0371                 if bbox is None:
0372                     bbox=(0, 0, self.itemsize[i][0]+extrawidth, self.itemsize[i][1])
0373                 startx=3+x*(self.itemsize[i][0]+self.ITEMPADDING+extrawidth)
0374                 startx+=bbox[0]
0375                 endx=startx+bbox[2]-bbox[0]
0376                 starty=posy+bbox[1]
0377                 endy=starty+bbox[3]-bbox[1]
0378                 if startx<=pointx<=endx and starty<=pointy<=endy:
0379                     ht=self.HitTestResult(location=self.HitTestResult.IN_ITEM,
0380                                           sectionnum=i, section=section,
0381                                           itemnum=num, item=item,
0382                                           itemx=pointx-startx+bbox[0],
0383                                           itemy=pointy-starty+bbox[1],
0384                                           itemrect=(startx, starty, endx-startx, endy-starty),
0385                                           itemrectscrolled=(startx, starty-origin, endx-startx, endy-starty),
0386                                           )
0387                     return ht
0388                 num+=1
0389             cury+=(len(self.items[i])+self.itemsperrow[i]-1)/self.itemsperrow[i]*(self.itemsize[i][1]+self.ITEMPADDING)
0390         return self.HitTestResult()
0391 
0392 
0393     def ReLayout(self):
0394         self.itemsperrow=[]
0395         self.vheight=0
0396         for i,section in enumerate(self.sections):
0397             self.itemsperrow.append(max((self._w-6)/(self.itemsize[i][0]+self.ITEMPADDING),1))
0398             if self.active_section!=None and section.label!=self.active_section:
0399                 continue
0400             self.vheight+=self.sectionheights[-1]
0401             rows=(len(self.items[i])+self.itemsperrow[i]-1)/self.itemsperrow[i]
0402             self.vheight+=rows*(self.itemsize[i][1]+self.ITEMPADDING)
0403 
0404         # set the height we want wx to think the window is
0405         self.maxheight=max(self.vheight,self._h)
0406         # adjust scrollbar
0407         self.SetScrollbars(0,1,0,self.vheight,0, self.GetViewStart()[1])
0408         self.SetScrollRate(0, self.VSCROLLPIXELS)
0409 
0410     def UpdateItems(self):
0411         "Called if you want the items to be refetched from the model"
0412         self.sections=self.datasource.GetSections()
0413         self.items=[]
0414         self.itemsize=[]
0415         self.sectionheights=[]
0416         self.selected=[]
0417         self.boundingboxes=[]
0418         for i,section in enumerate(self.sections):
0419             self.sectionheights.append(section.GetHeight())
0420             self.itemsize.append(self.datasource.GetItemSize(i,section))
0421             items=self.datasource.GetItemsFromSection(i,section)            
0422             self.items.append(items)
0423             self.boundingboxes.append( [None]*len(items) )
0424             self.selected.append( [False]*len(items) )
0425         self._w+=1 # cause a relayout to happen
0426         self.Refresh(False)
0427 
0428 
0429             
0430 def _isvisible(start, end, firstvisible, lastvisible):
0431     return start <= firstvisible <= end <= lastvisible or \
0432            (start >= firstvisible and start <= lastvisible) or \
0433            (start <= firstvisible and end >=lastvisible)
0434 
0435 
0436 class SectionHeader(object):
0437     "A generic section header implementation"
0438 
0439     def __init__(self, label):
0440         self.label=label
0441         self.InitAttributes()
0442 
0443     def InitAttributes(self):
0444         "Initialise our font and colours"
0445         self.font=wx.TheFontList.FindOrCreateFont(20, family=wx.SWISS, style=wx.NORMAL, weight=wx.NORMAL)
0446         self.font2=wx.TheFontList.FindOrCreateFont(20, family=wx.SWISS, style=wx.NORMAL, weight=wx.LIGHT)
0447         self.fontcolour=wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNTEXT)
0448         self.font2colour=wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNSHADOW)
0449         dc=wx.MemoryDC()
0450         # mac needs a bitmap selected in order to return textextent!
0451         if guihelper.IsMac():
0452             dc.SelectObject(wx.EmptyBitmap(100,100))
0453         w,h,d,l=dc.GetFullTextExtent("I", font=self.font)
0454         self.height=h+3
0455         self.descent=d
0456 
0457     def GetHeight(self):
0458         return self.height
0459 
0460     def Draw(self, dc, width):
0461         oldc=dc.GetTextForeground()
0462         oldf=dc.GetFont()
0463         dc.DrawLine(3, self.height-self.descent, width-3, self.height-self.descent)
0464         dc.SetTextForeground(self.font2colour)
0465         dc.SetFont(self.font2)
0466         for xoff in (0,1,2):
0467             for yoff in (0,1,2):
0468                 dc.DrawText(self.label, xoff+3, yoff)
0469         dc.SetTextForeground(self.fontcolour)
0470         dc.SetFont(self.font)
0471         dc.DrawText(self.label, 1+3,1)
0472         dc.SetTextForeground(oldc)
0473         dc.SetFont(oldf)
0474                 
0475 class Item(object):
0476     """A generic item implementation.
0477 
0478     You don't need to inherit from this - it is mainly to document what you have to implement."""
0479 
0480     def Draw(self, dc, width, height, selected):
0481         """Draw yourself into the available space.  0,0 will be your top left.
0482 
0483         Note that the width may be larger than the
0484         L{DataSource.GetItemSize} method returned because unused space
0485         is spread amongst the items.  It will never be smaller than
0486         what was returned.  You should set the clipping region if
0487         necessary.
0488 
0489         The main display code needs to know the bounding box for each item so that it can tell
0490         when an item has been clicked on, as opposed to the white space surrounding an item.
0491         By default it clears the bounding box and looks at what area you draw on in this
0492         function.  If you return None, then that is what happens.
0493 
0494         Instead you may also return a 4 item tuple of (minx, miny, maxx, maxy) and that
0495         will be used.
0496 
0497         @param dc:  The device context to draw into
0498         @param width: maximum space to use
0499         @param height: maximum space to use
0500         @param selected: if the item is currently selected"""
0501         raise NotImplementedError()
0502     
0503 
0504 
0505 class DataSource(object):
0506     """This is the model
0507 
0508     You don't need to inherit from this - it is mainly to document what you have to implement."""
0509 
0510     def GetSections(self):
0511         "Return a list of section headers"
0512         raise NotImplementedError()
0513 
0514     def GetItemSize(self, sectionnumber, sectionheader):
0515         "Return (width, height of each item)"
0516         return (160, 80)
0517 
0518     def GetItemsFromSection(self,sectionnumber,sectionheader):
0519         """Return a list of the items for the section.
0520 
0521         @param sectionnumber: the index into the list returned by L{GetSections}
0522         @param sectionheader: the section header object from that list
0523         """
0524         raise NotImplementedError()
0525 
0526 if __name__=="__main__":
0527 
0528 
0529 
0530     def demo():
0531         import wx
0532         app=wx.PySimpleApp()
0533 
0534         import sys
0535         import common
0536         sys.excepthook=common.formatexceptioneh
0537         import wx.html
0538         import os
0539         import brewcompressedimage
0540         import wallpaper
0541         import fileinfo
0542         import conversions
0543 
0544 
0545         # find bitpim wallpaper directory
0546         config=wx.Config("bitpim", style=wx.CONFIG_USE_LOCAL_FILE)
0547 
0548         p=config.Read("path", "resources")
0549         pn=os.path.join(p, "wallpaper")
0550         if os.path.isdir(pn):
0551             p=pn
0552 
0553         imagespath=p
0554         images=[name for name in os.listdir(imagespath) if name[-4:] in (".bci", ".bit", ".bmp", ".jpg", ".png")]
0555         images.sort()
0556         #images=images[:9]
0557 
0558         print imagespath
0559         print images
0560 
0561         class WallpaperManager:
0562 
0563             def GetImageStatInformation(self,name):
0564                 return wallpaper.statinfo(os.path.join(imagespath, name))    
0565 
0566             def GetImageConstructionInformation(self,file):
0567                 file=os.path.join(imagespath, file)
0568                 
0569                 if file.endswith(".mp4") or not os.path.isfile(file):
0570                     return guihelper.getresourcefile('wallpaper.png'), wx.Image
0571                 if self.isBCI(file):
0572                     return file, lambda name: brewcompressedimage.getimage(brewcompressedimage.FileInputStream(file))
0573                 # LG phones may return a proprietary wallpaper media file, LGBIT
0574                 fi=fileinfo.identify_imagefile(file)
0575                 if fi is not None and fi.format=='LGBIT':
0576                     return file, conversions.convertfilelgbittobmp
0577                 return file, wx.Image
0578 
0579             def isBCI(self, filename):
0580                 # is it a bci file?
0581                 return open(filename, "rb").read(4)=="BCI\x00"
0582 
0583 
0584         wx.FileSystem_AddHandler(wallpaper.BPFSHandler(WallpaperManager()))
0585 
0586         class TestItem(Item):
0587 
0588             def __init__(self, ds, secnum, itemnum, label):
0589                 super(TestItem,self).__init__()
0590                 self.label=label
0591                 self.ds=ds
0592                 self.secnum=secnum
0593                 self.itemnum=itemnum
0594 
0595             def Draw(self, dc, width, height, selected):
0596                 # uncomment to see exactly what size is given
0597                 #dc.DrawRectangle(0,0,width,height)
0598                 us=dc.GetUserScale()
0599                 dc.SetClippingRegion(0,0,width,height)
0600                 hdc=wx.html.HtmlDCRenderer()
0601                 hdc.SetDC(dc, 1)
0602                 hdc.SetSize(9999, 9999) # width is deliberately wide so that no wrapping happens
0603                 hdc.SetHtmlText(self.genhtml(selected), '.', True)
0604                 hdc.Render(0,0)
0605                 del hdc
0606                 # restore scale hdc messes
0607                 dc.SetUserScale(*us)
0608                 dc.DestroyClippingRegion()
0609 
0610                 # Linux gets bounding box wrong, so we deliberately return actual size
0611                 if guihelper.IsGtk():
0612                     return (0,0,width,height)
0613                 elif guihelper.IsMSWindows():
0614                     return max(0,dc.MinX()), max(0, dc.MinY()), min(width, dc.MaxX()), min(height, dc.MaxY())
0615 
0616             def genhtml(self, selected):
0617                 if selected:
0618                     selected='bgcolor="blue"'
0619                 else:
0620                     selected=""
0621                 return """<table %s><tr><td valign=top><p><img src="bpuserimage:%s;width=%d;height=%d;valign=top"><td valign=top><b>%s</b><br>BMP format<br>123x925<br>Camera</tr></table>""" \
0622                        % (selected, images[self.itemnum], self.ds.IMGSIZES[self.secnum][0], self.ds.IMGSIZES[self.secnum][1], self.label, )
0623 
0624         class TestDS(DataSource):
0625 
0626             SECTIONS=("Camera", "Wallpaper", "Oranges", "Lemons")
0627             ITEMSIZES=( (240,240), (160,70), (48,48), (160,70) )
0628             IMGSIZES=[ (w-110,h-20) for w,h in ITEMSIZES]
0629             IMGSIZES[2]=(16,16)
0630 
0631             def GetSections(self):
0632                 return [SectionHeader(x) for x in self.SECTIONS]
0633 
0634             def GetItemsFromSection(self, sectionnumber, sectionheader):
0635                 return [TestItem(self, sectionnumber, i, "%s-#%d" % (sectionheader.label,i)) for i in range(len(images))]
0636 
0637             def GetItemSize(self, sectionnumber, sectionheader):
0638                 return self.ITEMSIZES[sectionnumber]
0639 
0640         f=wx.Frame(None, title="Aggregate Display Test")
0641         ds=TestDS()
0642         d=Display(f,ds, "wallpaper-watermark")
0643         f.Show()
0644 
0645         app.MainLoop()
0646     
0647     
0648     if __debug__ and True:
0649         def profile(filename, command):
0650             import hotshot, hotshot.stats, os
0651             file=os.path.abspath(filename)
0652             profile=hotshot.Profile(file)
0653             profile.run(command)
0654             profile.close()
0655             del profile
0656             howmany=100
0657             stats=hotshot.stats.load(file)
0658             stats.strip_dirs()
0659             stats.sort_stats('time', 'calls')
0660             stats.print_stats(20)
0661             stats.sort_stats('cum', 'calls')
0662             stats.print_stats(20)
0663             stats.sort_stats('calls', 'time')
0664             stats.print_stats(20)
0665             sys.exit(0)
0666 
0667         profile("aggdisplay.prof", "demo()")
0668 
0669     else:
0670         demo()
0671         
0672     
0673 

Generated by PyXR 0.9.4