Hi,
Gtk only allows to specify a minimal widget size. To prevent it form growing, place it into a ScrolledWindow.
To fully control the “lessons” allocation, you can use a custom timetable widget implementing its do_size_allocate virtual method to place the lessons at their expected offset and height.
Quick and (very) dirty example, assuming a full 24h timespan:
import sys
import gi
gi.require_version('Gdk', '4.0')
gi.require_version('Gtk', '4.0')
from gi.repository import Gdk, Gtk
class Lesson(Gtk.ScrolledWindow):
__gtype_name__ = __qualname__
def __init__(self, start, duration, *labels, **kwargs):
Gtk.ScrolledWindow.__init__(self, **kwargs)
self.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.EXTERNAL)
self.add_css_class('lesson')
self.start = start
self.duration = duration
self.box = Gtk.Box(orientation='vertical')
for label in labels:
self.box.append(Gtk.Inscription(text=label))
self.set_child(self.box)
class TimeTable(Gtk.Widget):
__gtype_name__ = __qualname__
def __init__(self, **kwargs):
Gtk.Widget.__init__(self, **kwargs)
self.add_css_class('timetable')
def add_lesson(self, lesson):
lesson.set_parent(self)
def do_dispose(self):
for child in list(self):
child.unparent()
def do_measure(self, orientation, for_size):
w_min, w_nat, b_min, b_nat = 1, 1, -1, -1
for child in self:
c_min, c_nat, _, _ = child.measure(orientation, -1)
if orientation == Gtk.Orientation.VERTICAL:
w_min = max(w_min, 24 * c_min) # hacky, assumes all lessons duration >= 1h
else:
w_min = max(w_min, c_min)
w_nat = max(w_nat, c_nat)
w_nat = max(w_min, w_nat)
return w_min, w_nat, b_min, b_nat
def do_size_allocate(self, width, height, baseline):
rect = Gdk.Rectangle()
rect.x, rect.width = 0, width
for child in self:
rect.y = child.start * height / 24
rect.height = child.duration * height / 24
child.size_allocate(rect, baseline)
class MyAppWindow(Gtk.ApplicationWindow):
__gtype_name__ = __qualname__
def __init__(self):
Gtk.ApplicationWindow.__init__(self, title="Timetable", default_width=100, default_height=600)
timetable = TimeTable()
timetable.add_lesson(Lesson(8.0, 1.0, "DE", "OS", "O1"))
timetable.add_lesson(Lesson(10.0, 2.0, "MA", "DP", "O1"))
timetable.add_lesson(Lesson(14.0, 1.0, "GE", "HIP", "O1"))
# Optional: put the timetable in a scrolledwindow
self.set_child(timetable)
self.present()
class MyApp(Gtk.Application):
__gtype_name__ = __qualname__
def __init__(self):
Gtk.Application.__init__(self)
self.connect('startup', self.on_startup)
self.connect('activate', self.on_activate)
def on_startup(self, app):
css = Gtk.CssProvider()
css.load_from_string(".lesson {border: 1px solid @borders; border-radius: 6px; margin: 0 3px;}")
disp = Gdk.Display.get_default()
Gtk.StyleContext.add_provider_for_display(disp, css, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
def on_activate(self, app):
self.add_window(MyAppWindow())
if __name__ == '__main__':
sys.exit(MyApp().run(sys.argv))