Skip to content

Instantly share code, notes, and snippets.

@spillz
Created January 19, 2015 01:55
Show Gist options
  • Select an option

  • Save spillz/20a5e0c789a5238254be to your computer and use it in GitHub Desktop.

Select an option

Save spillz/20a5e0c789a5238254be to your computer and use it in GitHub Desktop.
GTK3 Conversion of Proportional Layout
from gi.repository import Gtk
from gi.repository import Gdk
from gi.repository import cairo
from gi.repository import GObject
class ProportionalLayoutChild:
def __init__(self,widget,left,right,top,bottom):
self.widget=widget
self.left=left
self.right=right
self.top=top
self.bottom=bottom
self.eventbox = None
self.hidden = False
class ProportionalLayout(Gtk.Container):
'''
An extension of Gtk.Container that supports sizing of children and positioning them
in proportional (instead of pixel) terms
'''
__gtype_name__ = 'ProportionalLayout'
def __init__(self,*children):
super(ProportionalLayout, self).__init__()
self.set_has_window(False)
self.children=[]
for ch in children:
self.add_with_bg(*ch)
def do_get_request_mode(self):
return(Gtk.SizeRequestMode.CONSTANT_SIZE)
def do_get_preferred_height_for_width(self, width):
needed_req = [0,0]
for ch in self.children:
req = ch.widget.get_preferred_height_for_width(width)
try:
req[0] = int(req[0]/(ch.top-ch.bottom))
except:
pass
try:
req[1] = int(req[0]/(ch.top-ch.bottom))
except:
pass
for i in range(2):
if needed_req[i]<req[i]:
needed_req[i]=req[i]
return tuple(needed_req)
def do_get_preferred_width_for_height(self, height):
needed_req = [0,0]
for ch in self.children:
req = ch.widget.get_preferred_width_for_height(height)
try:
req[0] = int(req[0]/(ch.right-ch.left))
except:
pass
try:
req[1] = int(req[1]/(ch.right-ch.left))
except:
pass
for i in range(2):
if needed_req[i]<req[i]:
needed_req[i]=req[i]
return tuple(needed_req)
def do_get_preferred_width(self):
'''
request the minimum size such that each child widget can fit within its specified proportions
'''
needed_req = [0,0]
for ch in self.children:
req = ch.widget.get_preferred_width()
try:
req[0] = int(req[0]/(ch.right-ch.left))
except:
pass
try:
req[1] = int(req[1]/(ch.right-ch.left))
except:
pass
for i in range(2):
if needed_req[i]<req[i]:
needed_req[i]=req[i]
return tuple(needed_req)
def do_get_preferred_height(self):
'''
request the minimum size such that each child widget can fit within its specified proportions
'''
needed_req = [0,0]
for ch in self.children:
req = ch.widget.get_preferred_width()
try:
req[0] = int(req[0]/(ch.top-ch.bottom))
except:
pass
try:
req[1] = int(req[0]/(ch.top-ch.bottom))
except:
pass
for i in range(2):
if needed_req[i]<req[i]:
needed_req[i]=req[i]
return tuple(needed_req)
def do_size_allocate (self, allocation):
n = len(self.children)
al = allocation
for ch in self.children:
widget = ch.eventbox if ch.eventbox else ch.widget
left = ch.left
right = ch.right
if left == right: #centered
w, wn = widget.get_preferred_width()
w = 0
left = int(al.x + left * al.width - w/2)
elif left is not None and right is not None:
w = int((right - left)*al.width)
w = 0
left = int(al.x + left * al.width)
elif left is not None: #align right
w, wn = widget.get_preferred_width()
w = 0
left = int(al.x + left * al.width)
elif right is not None: #align left
w, wn = widget.get_preferred_width()
w = 0
left = int(al.x + right * al.width - w)
top = ch.top
bottom = ch.bottom
if top == bottom: #centered
h, hn = widget.get_preferred_height()
h = 0
top = int(al.y + top * al.height - h/2)
elif top is not None and bottom is not None:
h = int((bottom - top)*al.height)
h = 0
top = int(al.y + top * al.height)
elif top is not None: #align bottom
h, hn = widget.get_preferred_height()
h = 0
top = int(al.y + top * al.height)
elif bottom is not None: #align top
h, hn = widget.get_preferred_height()
h = 0
top = int(al.x + bottom *al.height - h)
a=cairo.RectangleInt(left,top,w,h)
widget.size_allocate(a)
def do_remove(self,child):
i=0
for ch in self.children:
if ch.widget==child or ch.eventbox==child:
if ch.eventbox:
ch.eventbox.remove(ch.widget)
ch.eventbox.unparent()
else:
ch.widget.unparent()
del self.children[i]
return
i+=1
def add(self, widget, x_left, x_right, y_bottom, y_top):
ch = ProportionalLayoutChild(widget, x_left, x_right, y_bottom, y_top)
widget.set_parent(self)
self.children.append(ch)
self.queue_resize()
def do_forall (self, include_internals, callback):
try:
for ch in self.children:
if ch.eventbox:
callback (ch.eventbox)
else:
callback (ch.widget)
except AttributeError:
print 'AttribError'
GObject.type_register(ProportionalLayout)
if __name__ == '__main__':
proplayout = ProportionalLayout()
proplayout.add(Gtk.Button('bottom-right'),0.5,1,0.5,1)
box = Gtk.HBox()
box.pack_start(Gtk.Button("test"), True, True, 0)
box.pack_start(proplayout, True, True, 0)
window = Gtk.Window ()
window.add(box)
window.set_size_request(600,300)
window.connect('destroy', lambda window: Gtk.main_quit ())
window.show_all()
window.present ()
Gtk.main ()
@spillz
Copy link
Author

spillz commented Jan 19, 2015

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment