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