and then at some point later they do this:
I have been spending some of my spare time messing around with PyGTK, so here is some sample code in Python which does this thing.
import gtk
from zope.interface import Interface, implements, Attribute
class IMultiPlug(Interface):
"""Implements multi-plug stuff.
"""
def addPlug(plug, position=0):
"""
Add plug.
@param plug: implementor of IPlug
@param position: int - useful when using tabs or other visibly ordered
MPI interfaces
"""
def removePlug(plug=None):
"""
Remove a plug.
@param plug: implementor of IPlug
"""
def iterPlugs():
"""Return an iterator of all plugs
"""
class IPlug(Interface):
gtkwidget = Attribute('a gtk.Widget')
name = Attribute('a unicode name')
icon = Attribute('a gdk.Pixmap')
class Plug:
implements(IPlug)
def __init__(self, name, gtkwidget, icon=None):
self.name = name
self.gtkwidget = gtkwidget
if icon is None:
icon = gtk.icon_theme_get_default().load_icon(gtk.STOCK_YES,
64, 0)
self.icon = icon
class MultiWindow:
implements(IMultiPlug)
def __init__(self, prefix = ''):
self.windows = {}
self.plugs = []
self.prefix = prefix
def addPlug(self, plug, position=0):
win = gtk.Window()
win.set_title(self.prefix + plug.name)
self.windows[plug] = win
win.add(plug.gtkwidget)
win.show_all()
self.plugs.insert(position, plug)
def killit(ev):
self.removePlug(plug)
win.connect("delete_event", killit)
win.set_icon(plug.icon)
def iterPlugs(self):
return self.plugs[:]
def removePlug(self, plug):
for enum, oplug in enumerate(self.plugs):
if plug is oplug:
self.windows[plug].remove(plug.gtkwidget)
self.windows[plug].destroy()
self.plugs.pop(enum)
self.windows.pop(plug)
return
class MultiTab:
implements(IMultiPlug)
def __init__(self, notebook, window):
self.notebook = notebook
self.window = window
self.plugs = []
def labelFactory(self, plug):
hb = gtk.HBox()
# Icon box
icbox = gtk.Image()
scaled = plug.icon.scale_simple(16, 16, gtk.gdk.INTERP_BILINEAR)
icbox.set_from_pixbuf(scaled)
icbox.set_padding(2, 0)
hb.add(icbox)
# Label
hb.add(gtk.Label(plug.name))
# Close Button
cb = gtk.Button()
cb.set_relief(gtk.RELIEF_NONE)
im = gtk.Image()
im.set_from_pixbuf(gtk.icon_theme_get_default().load_icon(gtk.STOCK_CLOSE,
12, 0))
im.show_all()
cb.add(im)
hb.add(cb)
hb.set_child_packing(im, False, False, 0, gtk.PACK_START)
def killit(ev):
self.removePlug(plug)
cb.connect('clicked', killit)
return hb
def addPlug(self, plug, position=0):
lab = self.labelFactory(plug)
self.notebook.insert_page(plug.gtkwidget, lab, position)
self.plugs.insert(position, plug)
plug.gtkwidget.show_all()
lab.show_all()
self.window.show_all()
def removePlug(self, plug):
for enum, oplug in enumerate(self.plugs):
if oplug is plug:
self.plugs.pop(enum)
self.notebook.remove_page(enum)
break
if not self.plugs:
self.window.hide()
def iterPlugs(self):
return self.plugs[:]
class Cycler:
def __init__(self, mdi1, mdi2):
self.mdi1 = mdi1
self.mdi2 = mdi2
win = gtk.Window()
win.set_title("Cycler")
but = gtk.Button("cycle MDI")
but.set_size_request(200,200)
win.add(but)
win.connect('destroy', gtk.main_quit)
but.connect('clicked', self.swap)
win.show_all()
def swap(self, ev):
for plug in self.mdi1.iterPlugs():
self.mdi1.removePlug(plug)
self.mdi2.addPlug(plug)
self.mdi1, self.mdi2 = self.mdi2, self.mdi1
def test():
mdi1 = MultiWindow('MDI Demo: ')
n = gtk.Notebook()
nw = gtk.Window()
nw.set_title("MDI Notebook")
nw.add(n)
mdi2 = MultiTab(n, nw)
widgets = [gtk.Button('Button %d' % x) for x in range(4)]
import random
itheme = gtk.icon_theme_get_default()
for e, widget in enumerate(widgets):
widget.set_size_request(300,200)
mdi1.addPlug(Plug('Plug #%d'%e, widget, itheme.load_icon(random.choice(itheme.list_icons()),64,0) ))
Cycler(mdi1, mdi2)
gtk.main()
if __name__ == '__main__':
test()