home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2009 June / maximum-cd-2009-06.iso / DiscContents / digsby_setup.exe / lib / gui / pref / iconeditor.pyo (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2009-02-26  |  19.4 KB  |  536 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.5)
  3.  
  4. from __future__ import with_statement
  5. from __future__ import division
  6. from traceback import print_exc
  7. from util import debug_property
  8. import sys
  9. IMAGE_WILDCARD = 'Image files (*.bmp;*.gif;*.jpeg;*.jpg;*.png)|*.bmp;*.gif;*.jpeg;*.jpg;*.png|All files (*.*)|*.*'
  10. from wx import BufferedPaintDC, ImageFromString, Size, Point, GetMousePosition, Bitmap, ImageFromBitmap, BitmapFromImage
  11. from gui.windowfx import ApplySmokeAndMirrors
  12. import wx
  13. from PIL import Image
  14. from cStringIO import StringIO
  15. from util import traceguard, do
  16. from path import path
  17. from logging import getLogger
  18. log = getLogger('iconeditor')
  19. info = log.info
  20. MAX_BICON_SIZE = (128, 128)
  21.  
  22. class IconEditor(wx.Dialog):
  23.     def_size = (295, 415)
  24.     
  25.     def __init__(self, parent, icon = None):
  26.         wx.Dialog.__init__(self, parent, -1, _('Set Buddy Icon'), size = self.def_size)
  27.         self.Sizer = s = wx.BoxSizer(wx.VERTICAL)
  28.         self.ReturnCode = wx.ID_CANCEL
  29.         self.iconedit = IconEditPanel(self, icon)
  30.         s.Add(self.iconedit, 1, wx.EXPAND)
  31.         self.Fit()
  32.  
  33.     
  34.     def Bytes(self):
  35.         return self.iconedit.Bytes
  36.  
  37.     Bytes = property(Bytes)
  38.     
  39.     def ImageChanged(self):
  40.         return self.iconedit.dragger._image_changed
  41.  
  42.     ImageChanged = property(ImageChanged)
  43.     
  44.     def Prompt(self, okCallback):
  45.         self.okCallback = okCallback
  46.         self.Show(True)
  47.         
  48.         def onclose(e):
  49.             self.Show(False)
  50.             if self.ReturnCode in (wx.ID_SAVE, wx.ID_OK):
  51.                 self.okCallback()
  52.             
  53.             e.Skip(True)
  54.             wx.CallAfter(self.Destroy)
  55.  
  56.         self.Bind(wx.EVT_CLOSE, onclose)
  57.  
  58.  
  59.  
  60. class IconDragger(wx.Panel):
  61.     normal = 48
  62.     maxpick = 128
  63.     
  64.     def __init__(self, parent, slider):
  65.         wx.Panel.__init__(self, parent, style = wx.SUNKEN_BORDER)
  66.         Bind = self.Bind
  67.         Bind(wx.EVT_PAINT, self.on_paint)
  68.         Bind(wx.EVT_ERASE_BACKGROUND, (lambda e: pass))
  69.         Bind(wx.EVT_LEFT_DOWN, self.on_mouse_down)
  70.         Bind(wx.EVT_RIGHT_DOWN, self.on_right_down)
  71.         Bind(wx.EVT_LEFT_UP, self.on_mouse_up)
  72.         Bind(wx.EVT_MOTION, self.on_motion)
  73.         Bind(wx.EVT_MOUSE_CAPTURE_LOST, self.on_mouse_capture_lost)
  74.         Bind(wx.EVT_KEY_DOWN, self.on_key)
  75.         self.bitmap = wx.TransparentBitmap(32, 32)
  76.         self.adjustment = (0, 0)
  77.         self.dragging = False
  78.         self.picksize = wx.Size(self.normal, self.normal)
  79.         self.slider = slider
  80.         slider.Bind((wx.EVT_SLIDER,), (lambda e: self.on_slider(e, high_quality = False)))
  81.         slider.Bind((wx.EVT_SCROLL_CHANGED,), (lambda e: wx.CallAfter((lambda e = (e,): self.on_slider(e, high_quality = True)))
  82. ))
  83.         self._image_changed = False
  84.         self._image_bytes = None
  85.         sz = (260, 260)
  86.         self.SetMinSize(sz)
  87.         self.SetMaxSize(sz)
  88.         self.SetSize(sz)
  89.         SimpleDropTarget = SimpleDropTarget
  90.         import gui.toolbox.dnd
  91.         self.SetDropTarget(SimpleDropTarget(self))
  92.         self.SetCursor(wx.StockCursor(wx.CURSOR_HAND))
  93.  
  94.     
  95.     def OnDropFiles(self, filelist):
  96.         for filepath in (lambda .0: for f in .0:
  97. path(f))(filelist):
  98.             if filepath.exists():
  99.                 traceguard.__enter__()
  100.                 
  101.                 try:
  102.                     img = Image.open(filepath)
  103.                     img.load()
  104.                     return self.set_image(img.WX)
  105.                 finally:
  106.                     pass
  107.  
  108.                 continue
  109.             traceguard
  110.         
  111.         log.warning('no images in %r', filelist)
  112.  
  113.     
  114.     def OnDropBitmap(self, bitmap):
  115.         self.set_image(bitmap)
  116.  
  117.     
  118.     def on_slider(self, e = None, high_quality = True):
  119.         n = self.resize_func(self.slider.Value, high_quality = high_quality)
  120.         self.picksize = Size(n, n)
  121.         self.Refresh()
  122.         if e is not None:
  123.             self._image_changed = True
  124.             self._image_bytes = None
  125.         
  126.  
  127.     
  128.     def _resized_high(self, width, height):
  129.         return self.image.PIL.Resized((width, height))
  130.  
  131.     
  132.     def _resized_low(self, width, height):
  133.         return self.image.Scale(width, height)
  134.  
  135.     
  136.     def resize_image(self, dim, high_quality = True):
  137.         w = self.image.Width
  138.         h = self.image.Height
  139.         s = None if high_quality else self._resized_low
  140.         new_image = None if w < h else s(dim, (h / w) * dim)
  141.         self.bitmap = new_image.WXB
  142.  
  143.     
  144.     def on_paint(self, e = None):
  145.         dc = BufferedPaintDC(self)
  146.         b = wx.WHITE_BRUSH
  147.         dc.Brush = b
  148.         dc.Pen = wx.TRANSPARENT_PEN
  149.         dc.DrawRectangle(0, 0, *self.Size)
  150.         self.paint_bitmap(dc)
  151.         dc.Brush = wx.TRANSPARENT_BRUSH
  152.         dc.Pen = wx.RED_PEN
  153.         (x, y) = self.middle
  154.         x -= self.picksize[0] / 2
  155.         y -= self.picksize[1] / 2
  156.         dc.SetLogicalFunction(wx.INVERT)
  157.         dc.DrawRectangle(x, y, self.picksize[0], self.picksize[1])
  158.  
  159.     
  160.     def paint_bitmap(self, dc, pickerPos = None):
  161.         bw = self.bitmap.Width
  162.         bh = self.bitmap.Height
  163.         imagecenter = Point(self.Rect.Width / 2, self.Rect.Height / 2) - Point(bw / 2, bh / 2)
  164.         xy = imagecenter + (self.adjustment[0] * bw, self.adjustment[1] * bh)
  165.         if dc is not None:
  166.             dc.DrawBitmap(self.bitmap, *xy)
  167.         else:
  168.             pickWidth = int(self.picksize[0])
  169.             pickHeight = int(self.picksize[1])
  170.             if not pickerPos:
  171.                 pass
  172.             pickRect = wx.RectPS((self.Rect.width // 2 - self.picksize[0] // 2, self.Rect.height // 2 - self.picksize[1] // 2), (pickWidth, pickHeight))
  173.             pickRect.Position -= xy
  174.             imageRect = wx.RectPS((0, 0), (bw, bh))
  175.             cropRect = imageRect.Intersect(pickRect)
  176.             crop_box = (cropRect.left, cropRect.top, cropRect.right, cropRect.bottom)
  177.             croppedImage = self.bitmap.PIL.crop(crop_box)
  178.             offsetX = max(-(pickRect.x - cropRect.x), 0)
  179.             offsetY = max(-(pickRect.y - cropRect.y), 0)
  180.             if offsetX or offsetY:
  181.                 paddedImage = Image.new('RGBA', (pickRect.width, pickRect.height), (0, 0, 0, 0))
  182.                 paddedImage.paste(croppedImage, (offsetX, offsetY))
  183.                 return paddedImage
  184.             
  185.             return croppedImage
  186.  
  187.     
  188.     def middle(self):
  189.         (w, h) = self.Size
  190.         return Point(w / 2, h / 2)
  191.  
  192.     middle = property(middle)
  193.     
  194.     def Bytes(self):
  195.         s = self.picksize
  196.         r = self.Rect
  197.         pickerPos = (r.Width // 2 - s[0] // 2, r.Height // 2 - s[1] // 2)
  198.         img = self.paint_bitmap(None, pickerPos)
  199.         imgFile = StringIO()
  200.         img.save(imgFile, 'PNG', optimize = True)
  201.         return imgFile.getvalue()
  202.  
  203.     Bytes = debug_property(Bytes)
  204.     
  205.     def on_mouse_capture_lost(self, event):
  206.         self.CancelDrag()
  207.  
  208.     
  209.     def on_mouse_down(self, e):
  210.         e.Skip()
  211.         if e.LeftDown():
  212.             self.startdrag = self.dragging = GetMousePosition()
  213.             self.CaptureMouse()
  214.         
  215.  
  216.     
  217.     def on_right_down(self, event):
  218.         if self.dragging:
  219.             self.CancelDrag()
  220.         else:
  221.             event.Skip()
  222.  
  223.     
  224.     def on_key(self, event):
  225.         isesc = event.KeyCode == wx.WXK_ESCAPE
  226.         if self.dragging and isesc:
  227.             self.CancelDrag()
  228.         elif not isesc:
  229.             event.Skip()
  230.         
  231.  
  232.     
  233.     def CancelDrag(self):
  234.         startdrag = self.startdrag
  235.         curdrag = self.dragging
  236.         self.on_mouse_up()
  237.         self.dragging = curdrag
  238.         self.on_motion(forcednewpos = startdrag)
  239.         self.dragging = False
  240.  
  241.     
  242.     def on_motion(self, e = None, forcednewpos = None):
  243.         if self.dragging is not False:
  244.             if not forcednewpos:
  245.                 pass
  246.             newpos = GetMousePosition()
  247.             delta = newpos - Point(*self.dragging)
  248.             diff = (float(delta.x) / self.bitmap.Width, float(delta.y) / self.bitmap.Height)
  249.             self.adjustment = (self.adjustment[0] + diff[0], self.adjustment[1] + diff[1])
  250.             self.dragging = newpos
  251.             self.Refresh()
  252.             self._image_changed = True
  253.             self._image_bytes = None
  254.         
  255.  
  256.     
  257.     def on_mouse_up(self, e = None):
  258.         if not e or e.LeftUp():
  259.             self.startdrag = None
  260.             self.dragging = False
  261.             while self.HasCapture():
  262.                 self.ReleaseMouse()
  263.         
  264.  
  265.     
  266.     def set_image(self, image, first = False):
  267.         self.Parent.set_screen_button_mode()
  268.         if isinstance(image, str):
  269.             log.info('set_image received bytes')
  270.             self._image_bytes = image
  271.             image = ImageFromString(image)
  272.         
  273.         if not first:
  274.             self._image_changed = True
  275.         
  276.         self._set_imageorbitmap(image)
  277.         self.dim = max(self.image.Width, self.image.Height)
  278.         if self.dim > max(MAX_BICON_SIZE):
  279.             self._image_changed = True
  280.         
  281.         self.adjustment = (0, 0)
  282.         if self.image.Width == self.normal and self.image.Height == self.normal:
  283.             self.slider.Enable(False)
  284.             self.picksize = Size(self.normal, self.normal)
  285.         else:
  286.             self.slider.Enable(True)
  287.             if self.dim < self.normal:
  288.                 f = self.f1
  289.             elif self.dim < self.maxpick:
  290.                 f = self.f2
  291.             else:
  292.                 f = self.f3
  293.             self.resize_func = f
  294.             self.on_slider()
  295.         self.Refresh()
  296.  
  297.     
  298.     def f1(self, val, high_quality = True):
  299.         return self.normal - int((self.normal - self.dim) * (val / 100))
  300.  
  301.     
  302.     def f2(self, val, high_quality = True):
  303.         return self.dim - (val / 100) * (self.dim - self.normal)
  304.  
  305.     
  306.     def f3(self, val, high_quality = True):
  307.         mid = 50
  308.         pickval = val - mid
  309.         if pickval < 0:
  310.             pickval = 0
  311.         
  312.         if val < mid:
  313.             dim = (self.dim - self.maxpick) * (val / mid) + self.maxpick
  314.             self.resize_image(dim, high_quality = high_quality)
  315.         else:
  316.             self.resize_image(max(self.image.Width, self.image.Height), high_quality = high_quality)
  317.         return self.maxpick - (pickval / mid) * (self.maxpick - self.normal)
  318.  
  319.     
  320.     def _set_imageorbitmap(self, image):
  321.         if isinstance(image, Bitmap):
  322.             self.image = ImageFromBitmap(image)
  323.             if not self.image.HasAlpha():
  324.                 self.image.InitAlpha()
  325.             
  326.             self.bitmap = image
  327.         elif isinstance(image, wx.Image):
  328.             self.image = image
  329.             if not image.HasAlpha():
  330.                 image.InitAlpha()
  331.             
  332.             self.bitmap = BitmapFromImage(self.image)
  333.         else:
  334.             raise TypeError
  335.  
  336.  
  337.  
  338. class IconEditPanel(wx.Panel):
  339.     
  340.     def __init__(self, parent, bitmap = None):
  341.         wx.Panel.__init__(self, parent)
  342.         wx.InitAllImageHandlers()
  343.         self.construct_and_layout()
  344.         for b in 'file clipboard screen save clear cancel'.split():
  345.             self.buttonfor(b).Bind(wx.EVT_BUTTON, getattr(self, 'on_' + b))
  346.         
  347.         if bitmap:
  348.             if not hasattr(bitmap, 'IsOk') or bitmap.IsOk():
  349.                 traceguard.__enter__()
  350.                 
  351.                 try:
  352.                     self.set_image(bitmap, first = True)
  353.                 finally:
  354.                     pass
  355.  
  356.             
  357.         
  358.  
  359.     
  360.     def Bytes(self):
  361.         if self.dragger._image_bytes and not (self.dragger._image_changed):
  362.             log.info('returning original image bytes')
  363.             return self.dragger._image_bytes
  364.         else:
  365.             log.info('returning new bytes from resized image')
  366.             return self.dragger.Bytes
  367.  
  368.     Bytes = property(Bytes)
  369.     
  370.     def on_file(self, e):
  371.         filediag = wx.FileDialog(wx.GetTopLevelParent(self), _('Choose an icon'), wildcard = IMAGE_WILDCARD)
  372.         if filediag.ShowModal() == wx.ID_OK:
  373.             imgpath = path(filediag.GetPath())
  374.             if imgpath.exists():
  375.                 
  376.                 try:
  377.                     Image.open(imgpath).load()
  378.                 except:
  379.                     wx.MessageBox(_('"%s"\n\nis not a valid image.') % imgpath, _('Invalid Image'), style = wx.ICON_ERROR, parent = self)
  380.  
  381.                 self.set_image(imgpath.bytes())
  382.             
  383.         
  384.  
  385.     
  386.     def on_webcam(self, e):
  387.         pass
  388.  
  389.     capture_related = 'save'.split()
  390.     
  391.     def set_image(self, img, *a, **k):
  392.         return self.dragger.set_image(img, *a, **k)
  393.  
  394.     
  395.     def on_screen(self, e):
  396.         b = self.buttonfor('screen')
  397.         if b.Label == _('Capture'):
  398.             return self.on_capture()
  399.         
  400.         b = self.buttonfor('screen')
  401.         b.Label = _('Capture')
  402.         b.SetBold()
  403.         self.slider.Enable(False)
  404.         for b in self.capture_related:
  405.             self.buttonfor(b).Enable(False)
  406.         
  407.         cuthole(self.dragger)
  408.  
  409.     
  410.     def on_capture(self):
  411.         self.slider.Enable(True)
  412.         dragger = self.dragger
  413.         self.Freeze()
  414.         
  415.         try:
  416.             if sys.platform.startswith('win'):
  417.                 
  418.                 try:
  419.                     getScreenBitmap = getScreenBitmap
  420.                     import cgui
  421.                 except ImportError:
  422.                     print_exc()
  423.                     return None
  424.  
  425.                 bitmap = getScreenBitmap(wx.RectPS(dragger.ScreenRect.Position, dragger.ClientSize))
  426.             else:
  427.                 screendc = wx.ScreenDC()
  428.                 bitmap = screendc.GetAsBitmap()
  429.             if bitmap is not None:
  430.                 self.set_image(wx.ImageFromBitmap(bitmap))
  431.             
  432.             s = self.slider
  433.             s.Value = (s.Max - s.Min) / 2
  434.         finally:
  435.             wx.CallAfter(self.ThawLater)
  436.  
  437.  
  438.     
  439.     def ThawLater(self):
  440.         
  441.         try:
  442.             self.dragger.on_slider()
  443.         finally:
  444.             self.Thaw()
  445.  
  446.  
  447.     
  448.     def set_screen_button_mode(self):
  449.         b = self.buttonfor('screen')
  450.         if b.Label == _('Capture'):
  451.             b.Label = _('Screen')
  452.             f = b.Font
  453.             f.SetWeight(wx.FONTWEIGHT_NORMAL)
  454.             b.Font = f
  455.             (do,)((lambda .0: for b in .0:
  456. self.buttonfor(b).Enable(True))(self.capture_related))
  457.             ApplySmokeAndMirrors(wx.GetTopLevelParent(self))
  458.         
  459.  
  460.     
  461.     def on_clipboard(self, e):
  462.         cb = wx.TheClipboard
  463.         if cb.IsSupported(wx.DataFormat(wx.DF_BITMAP)):
  464.             data = wx.BitmapDataObject()
  465.             cb.GetData(data)
  466.             self.set_image(data.Bitmap)
  467.         else:
  468.             wx.MessageBox('No image data found in clipboard.', 'Icon From Clipboard')
  469.  
  470.     
  471.     def on_save(self, e):
  472.         self.EndWithReturnCode(wx.ID_OK)
  473.  
  474.     
  475.     def EndWithReturnCode(self, code):
  476.         win = wx.GetTopLevelParent(self)
  477.         while self.dragger.HasCapture():
  478.             self.dragger.ReleaseMouse()
  479.         win.ReturnCode = code
  480.         win.Close()
  481.  
  482.     
  483.     def on_clear(self, e):
  484.         self.set_image(wx.TransparentBitmap(100, 100))
  485.  
  486.     
  487.     def on_cancel(self, e):
  488.         self.EndWithReturnCode(wx.ID_CANCEL)
  489.  
  490.     
  491.     def construct_and_layout(self):
  492.         top = wx.StaticBoxSizer(wx.StaticBox(self, -1, 'Source'), wx.HORIZONTAL)
  493.         middle = wx.StaticBoxSizer(wx.StaticBox(self, -1, 'Preview'), wx.VERTICAL)
  494.         names = '&File Cli&pboard Scree&n &Save C&lear &Cancel'.split()
  495.         self.buttonnames = [ n.replace('&', '').lower() for n in names ]
  496.         self.buttons = [ wx.Button(self, -1, name) for name in names ]
  497.         []([ (b, 1, wx.EXPAND | wx.ALL, 3) for b in self.buttons[:3] ])
  498.         self.slider = wx.Slider(self)
  499.         self.slider.Disable()
  500.         self.dragger = IconDragger(self, self.slider)
  501.         middle.Add(self.dragger, 1, wx.EXPAND | wx.ALL)
  502.         middle.Add(self.slider, 0, wx.EXPAND | wx.ALL)
  503.         bottom = wx.BoxSizer(wx.HORIZONTAL)
  504.         []([ (b, 1, wx.EXPAND | wx.ALL, 3) for b in self.buttons[3:] ])
  505.         sz.AddMany([
  506.             (top, 0, wx.EXPAND | wx.ALL, 3),
  507.             (middle, 1, wx.EXPAND | wx.ALL, 3),
  508.             (bottom, 0, wx.EXPAND | wx.ALL, 3)])
  509.  
  510.     
  511.     def buttonfor(self, s):
  512.         return self.buttons[self.buttonnames.index(s)]
  513.  
  514.  
  515.  
  516. def cuthole(ctrl):
  517.     top = wx.GetTopLevelParent(ctrl)
  518.     x = ctrl.ScreenRect.X - top.ScreenRect.X
  519.     y = ctrl.ScreenRect.Y - top.ScreenRect.Y
  520.     (w, h) = ctrl.ClientSize
  521.     winsz = top.Size
  522.     region = wx.Region(0, 0, winsz[0], y)
  523.     region.UnionRect((0, 0, x, winsz[1]))
  524.     region.UnionRect((x + w, y, winsz[0] - w - x, h))
  525.     region.UnionRect((0, y + h, winsz[0], winsz[1] - h - y))
  526.     ApplySmokeAndMirrors(top, region)
  527.  
  528. if __name__ == '__main__':
  529.     
  530.     _ = lambda s: s
  531.     from gui.toolbox import setuplogging
  532.     setuplogging()
  533.     app = wx.PySimpleApp()
  534.     IconEditor(None).ShowModal()
  535.  
  536.