diff options
author | Johan Dahlin <johan@src.gnome.org> | 2006-01-19 19:12:11 +0000 |
---|---|---|
committer | Johan Dahlin <johan@src.gnome.org> | 2006-01-19 19:12:11 +0000 |
commit | ec718aaf077d2fabe791cb6a00acfd12454ce4cc (patch) | |
tree | 1b8f1ffe104cc4ee4ec476faea244a69f546a897 /examples/gtk/scrollable.py | |
parent | 6b5a8a60c481e162f1947fb82992156b2155b5b1 (diff) | |
download | pygtk-ec718aaf077d2fabe791cb6a00acfd12454ce4cc.tar.gz |
Install examples
* examples/Makefile.am:
Install examples
* examples/gtk/widget.py:
Call unrealize too
* examples/gtk/scrollable.py:
Add example of a scrollable widget
Diffstat (limited to 'examples/gtk/scrollable.py')
-rw-r--r-- | examples/gtk/scrollable.py | 278 |
1 files changed, 278 insertions, 0 deletions
diff --git a/examples/gtk/scrollable.py b/examples/gtk/scrollable.py new file mode 100644 index 00000000..6df15e55 --- /dev/null +++ b/examples/gtk/scrollable.py @@ -0,0 +1,278 @@ +# +# Reimplementation of gtk.Layout in python +# Example on how to implement a scrollable container in python +# +# Johan Dahlin <johan@gnome.org>, 2006 +# +# Requires PyGTK 2.8.0 or later + +import gobject +import gtk +from gtk import gdk + +class Child: + widget = None + x = 0 + y = 0 + +def set_adjustment_upper(adj, upper, always_emit): + changed = False + value_changed = False + + min = max(0.0, upper - adj.page_size) + + if upper != adj.upper: + adj.upper = upper + changed = True + + if adj.value > min: + adj.value = min + value_changed = True + + if changed or always_emit: + adj.changed() + if value_changed: + adj.value_changed() + +def new_adj(): + return gtk.Adjustment(0.0, 0.0, 0.0, + 0.0, 0.0, 0.0) + +class Layout(gtk.Container): + __gsignals__ = dict(set_scroll_adjustments= + (gobject.SIGNAL_RUN_LAST, None, + (gtk.Adjustment, gtk.Adjustment))) + def __init__(self): + self._children = [] + self._width = 100 + self._height = 100 + self._hadj = None + self._vadj = None + self._bin_window = None + self._hadj_changed_id = -1 + self._vadj_changed_id = -1 + gtk.Container.__init__(self) + + if not self._hadj or not self._vadj: + self._set_adjustments(self._vadj or new_adj(), + self._hadj or new_adj()) + + # Public API + + def put(self, widget, x=0, y=0): + child = Child() + child.widget = widget + child.x = x + child.y = y + self._children.append(child) + + if self.flags() & gtk.REALIZED: + widget.set_parent_window(self._bin_window) + + widget.set_parent(self) + + def set_size(self, width, height): + if self._width != width: + self._width = width + if self._height != height: + self._height = height + if self._hadj: + set_adjustment_upper(self._hadj, self._width, False) + if self._vadj: + set_adjustment_upper(self._vadj, self._height, False) + + if self.flags() & gtk.REALIZED: + self._bin_window.resize(max(width, self.allocation.width), + max(height, self.allocation.height)) + + # GtkWidget + + def do_realize(self): + self.set_flags(self.flags() | gtk.REALIZED) + + self.window = gdk.Window( + self.get_parent_window(), + window_type=gdk.WINDOW_CHILD, + x=self.allocation.x, + y=self.allocation.y, + width=self.allocation.width, + height=self.allocation.height, + wclass=gdk.INPUT_OUTPUT, + colormap=self.get_colormap(), + event_mask=gdk.VISIBILITY_NOTIFY_MASK) + self.window.set_user_data(self) + + self._bin_window = gdk.Window( + self.window, + window_type=gdk.WINDOW_CHILD, + x=int(-self._hadj.value), + y=int(-self._vadj.value), + width=max(self._width, self.allocation.width), + height=max(self._height, self.allocation.height), + colormap=self.get_colormap(), + wclass=gdk.INPUT_OUTPUT, + event_mask=(self.get_events() | gdk.EXPOSURE_MASK | + gdk.SCROLL_MASK)) + self._bin_window.set_user_data(self) + + self.set_style(self.style.attach(self.window)) + self.style.set_background(self.window, gtk.STATE_NORMAL) + self.style.set_background(self._bin_window, gtk.STATE_NORMAL) + + for child in self._children: + child.widget.set_parent_window(self._bin_window) + self.queue_resize() + + def do_unrealize(self): + self._bin_window.set_user_data(None) + self._bin_window = None + gtk.Container.do_unrealize(self) + + def _do_style_set(self, style): + gtk.Widget.do_style_set(self, style) + + if self.flags() & gtk.REALIZED: + self.style.set_background(self._bin_window, gtk.STATE_NORMAL) + + def do_expose_event(self, event): + if event.window != self._bin_window: + return False + gtk.Container.do_expose_event(self, event) + return False + + def do_map(self): + self.set_flags(self.flags() | gtk.MAPPED) + for child in self._children: + flags = child.widget.flags() + if flags & gtk.VISIBLE: + if not (flags & gtk.MAPPED): + child.widget.map() + self._bin_window.show() + self.window.show() + + def do_size_request(self, req): + req.width = 0 + req.height = 0 + for child in self._children: + child.widget.size_request() + + def do_size_allocate(self, allocation): + for child in self._children: + self._allocate_child(child) + + if self.flags() & gtk.REALIZED: + self.window.move_resize(*allocation) + self._bin_window.resize(max(self._width, allocation.width), + max(self._height, allocation.height)) + + self._hadj.page_size = allocation.width + self._hadj.page_increment = allocation.width * 0.9 + self._hadj.lower = 0 + set_adjustment_upper(self._hadj, + max(allocation.width, self._width), True) + + self._vadj.page_size = allocation.height + self._vadj.page_increment = allocation.height * 0.9 + self._vadj.lower = 0 + self._vadj.upper = max(allocation.height, self._height) + set_adjustment_upper(self._vadj, + max(allocation.height, self._height), True) + + def do_set_scroll_adjustments(self, hadj, vadj): + self._set_adjustments(hadj, vadj) + + # GtkContainer + + def do_forall(self, include_internals, callback, data): + for child in self._children: + callback(child.widget, data) + + def do_add(self, widget): + self.put(widget) + + def do_remove(self, widget): + child = self._get_child_from_widget(widget) + self._children.remove(child) + widget.unparent() + + # Private + + def _set_adjustments(self, hadj, vadj): + if not hadj and self._hadj: + hadj = new_adj() + + if not vadj and self._vadj: + vadj = new_adj() + + if self._hadj and self._hadj != hadj: + self._hadj.disconnect(self._hadj_changed_id) + + if self._vadj and self._vadj != vadj: + self._vadj.disconnect(self._vadj_changed_id) + + need_adjust = False + + if self._hadj != hadj: + self._hadj = hadj + set_adjustment_upper(hadj, self._width, False) + self._hadj_changed_id = hadj.connect( + "value-changed", + self._adjustment_changed) + need_adjust = True + + if self._vadj != vadj: + self._vadj = vadj + set_adjustment_upper(vadj, self._height, False) + self._vadj_changed_id = vadj.connect( + "value-changed", + self._adjustment_changed) + need_adjust = True + + if need_adjust and vadj and hadj: + self._adjustment_changed() + + def _adjustment_changed(self, adj=None): + if self.flags() & gtk.REALIZED: + self._bin_window.move(int(-self._hadj.value), + int(-self._vadj.value)) + self._bin_window.process_updates(True) + + def _get_child_from_widget(self, widget): + for child in self._children: + if child.widget == widget: + return child + else: + raise AssertionError + + def _allocate_child(self, child): + allocation = gdk.Rectangle() + allocation.x = child.x + allocation.y = child.y + req = child.widget.get_child_requisition() + allocation.width = req[0] + allocation.height = req[1] + child.widget.size_allocate(allocation) + +Layout.set_set_scroll_adjustments_signal('set-scroll-adjustments') + +def main(): + window = gtk.Window() + window.set_size_request(300, 300) + window.connect('delete-event', gtk.main_quit) + + sw = gtk.ScrolledWindow() + sw.set_policy(gtk.POLICY_ALWAYS, gtk.POLICY_ALWAYS) + window.add(sw) + + layout = Layout() + layout.set_size(1000, 1000) + sw.add(layout) + + b = gtk.Button('foobar') + layout.put(b, 100, 100) + + window.show_all() + gtk.main() + +if __name__ == '__main__': + main() |