From: Andrew Chadwick Date: Sat, 17 Sep 2011 00:25:17 +0000 (+0100) Subject: glade: wrap concrete elastic container/content X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=fef57f5daf328accab5546214be8a697dba2a428;p=mypaint-anime%2Fmaster.git glade: wrap concrete elastic container/content Factor elastic containers and components out to their own module and add a trivial ElasticWindow that can be built on later. Add the concrete classes we have to the glade library, though it's mostly the expander / window relationship we really care about. --- diff --git a/glade/icons/hicolor/16x16/actions/widget-mypaint-elastic-expander.png b/glade/icons/hicolor/16x16/actions/widget-mypaint-elastic-expander.png new file mode 100644 index 0000000..279c857 Binary files /dev/null and b/glade/icons/hicolor/16x16/actions/widget-mypaint-elastic-expander.png differ diff --git a/glade/icons/hicolor/16x16/actions/widget-mypaint-elastic-vbox.png b/glade/icons/hicolor/16x16/actions/widget-mypaint-elastic-vbox.png new file mode 100644 index 0000000..b17a134 Binary files /dev/null and b/glade/icons/hicolor/16x16/actions/widget-mypaint-elastic-vbox.png differ diff --git a/glade/icons/hicolor/16x16/actions/widget-mypaint-elastic-window.png b/glade/icons/hicolor/16x16/actions/widget-mypaint-elastic-window.png new file mode 100644 index 0000000..7d165ec Binary files /dev/null and b/glade/icons/hicolor/16x16/actions/widget-mypaint-elastic-window.png differ diff --git a/glade/icons/hicolor/22x22/actions/widget-mypaint-elastic-expander.png b/glade/icons/hicolor/22x22/actions/widget-mypaint-elastic-expander.png new file mode 100644 index 0000000..4bc28b7 Binary files /dev/null and b/glade/icons/hicolor/22x22/actions/widget-mypaint-elastic-expander.png differ diff --git a/glade/icons/hicolor/22x22/actions/widget-mypaint-elastic-vbox.png b/glade/icons/hicolor/22x22/actions/widget-mypaint-elastic-vbox.png new file mode 100644 index 0000000..eee47af Binary files /dev/null and b/glade/icons/hicolor/22x22/actions/widget-mypaint-elastic-vbox.png differ diff --git a/glade/icons/hicolor/22x22/actions/widget-mypaint-elastic-window.png b/glade/icons/hicolor/22x22/actions/widget-mypaint-elastic-window.png new file mode 100644 index 0000000..59dfd89 Binary files /dev/null and b/glade/icons/hicolor/22x22/actions/widget-mypaint-elastic-window.png differ diff --git a/glade/mypaint_widgets.py b/glade/mypaint_widgets.py index 75cc85d..ee082ba 100644 --- a/glade/mypaint_widgets.py +++ b/glade/mypaint_widgets.py @@ -4,4 +4,4 @@ from gui.tileddrawwidget import TiledDrawWidget from gui.pixbuflist import PixbufList - +from gui.elastic import ElasticWindow, ElasticVBox, ElasticExpander diff --git a/glade/mypaint_widgets.xml b/glade/mypaint_widgets.xml index 0c74259..7a6caef 100644 --- a/glade/mypaint_widgets.xml +++ b/glade/mypaint_widgets.xml @@ -16,11 +16,22 @@ generic-name="tdw" /> + + + + + + + diff --git a/gui/brushselectionwindow.py b/gui/brushselectionwindow.py index c4b8941..52fc650 100644 --- a/gui/brushselectionwindow.py +++ b/gui/brushselectionwindow.py @@ -14,7 +14,7 @@ from gettext import gettext as _ import windowing import stock import pixbuflist, dialogs, brushmanager -from layout import ElasticExpander +from elastic import ElasticExpander from brushlib import brushsettings class ToolWidget (gtk.VBox): diff --git a/gui/colorsamplerwindow.py b/gui/colorsamplerwindow.py index 53a05c6..95d4311 100755 --- a/gui/colorsamplerwindow.py +++ b/gui/colorsamplerwindow.py @@ -5,7 +5,7 @@ import struct import cairo import windowing import stock -from layout import ElasticExpander +from elastic import ElasticExpander from lib.helpers import rgb_to_hsv, hsv_to_rgb, clamp from gettext import gettext as _ import gobject diff --git a/gui/elastic.py b/gui/elastic.py new file mode 100644 index 0000000..716fb9c --- /dev/null +++ b/gui/elastic.py @@ -0,0 +1,169 @@ +# This file is part of MyPaint. +# Copyright (C) 2011 by Andrew Chadwick +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +import gtk +from gtk import gdk + + +class ElasticContainer: + """Mixin for containers which mirror certain size changes of descendents + + Descendents which wish to report internally-generated size changes should + add the ElasticContent mixin, and should be packed into a container that + derives from ElasticContainer. More than one ElasticContent widget can be + packed under an ElasticContainer, and each can report different types of + resizes - however the sub-hierarchies cannot overlap. You -can- nest + ElasticContainers though: it's the outer one that receives the resize + request. + """ + + def __init__(self): + """Mixin constructor (construct as a gtk.Widget before calling) + """ + self.__last_size = None + self.__saved_size_request = None + + def mirror_elastic_content_resize(self, dx, dy): + """Resize by a given amount. + + This is called by some ElasticContent widget below here in the + hierarchy when it notices a request-size change on itself. + """ + p = self.parent + while p is not None: + if isinstance(p, ElasticContainer): + # propagate up and don't handle here + p.mirror_elastic_content_resize(dx, dy) + return + p = p.parent + self.__saved_size_request = self.get_size_request() + alloc = self.get_allocation() + w = alloc.width+dx + h = alloc.height+dy + if isinstance(self, gtk.Window): + self.resize(w, h) + self.set_size_request(w, h) + self.queue_resize() + + +class ElasticContent: + """Mixin for GTK widgets which want some parent to change size to match. + """ + + def __init__(self, mirror_vertical=True, mirror_horizontal=True): + """Mixin constructor (construct as a gtk.Widget before calling) + + The options control which size changes are reported to the + ElasticContainer ancestor and how: + + `mirror_vertical`: + mirror vertical size changes + + `mirror_horizontal`: + mirror horizontal size changes + + """ + self.__vertical = mirror_vertical + self.__horizontal = mirror_horizontal + if not mirror_horizontal and not mirror_vertical: + return + self.__last_req = None + self.__expose_connid = self.connect_after("expose-event", + self.__after_expose_event) + self.__notify_parent = False + self.connect_after("size-request", self.__after_size_request) + + def __after_expose_event(self, widget, event): + # Begin notifying changes to the ancestor after the first expose event. + # It doesn't matter for widgets that know their size before hand. + # Assume widgets which initially don't know their size *do* know their + # proper size after their first draw, even if they drew themselves + # wrongly and now have to resize and do another size-request... + connid = self.__expose_connid + if not connid: + return + self.__expose_connid = None + self.__notify_parent = True + self.disconnect(connid) + + def __after_size_request(self, widget, req): + # Catch the final value of each size-request, calculate the + # difference needed and throw it back up the widget hierarchy + # to interested parties. + if not self.__last_req: + dx, dy = 0, 0 + else: + w0, h0 = self.__last_req + dx, dy = req.width - w0, req.height - h0 + self.__last_req = (req.width, req.height) + if not self.__notify_parent: + return + p = self.parent + while p is not None: + if isinstance(p, ElasticContainer): + if not self.__vertical: + dy = 0 + if not self.__horizontal: + dx = 0 + if dy != 0 or dx != 0: + p.mirror_elastic_content_resize(dx, dy) + break + if isinstance(p, ElasticContent): + break + p = p.parent + + +# XXX unused, may remove +class ElasticVBox (gtk.VBox, ElasticContainer): + __gtype_name__ = "ElasticVBox" + + def __init__(self, *args, **kwargs): + gtk.VBox.__init__(self, *args, **kwargs) + ElasticContainer.__init__(self) + + +class ElasticExpander (gtk.Expander, ElasticContent): + """Buildable elastic-content version of a regular GtkExpander. + """ + __gtype_name__ = "ElasticExpander" + + def __init__(self, *args, **kwargs): + gtk.Expander.__init__(self, *args, **kwargs) + ElasticContent.__init__(self, mirror_horizontal=False, + mirror_vertical=True) + + +class ElasticWindow (gtk.Window, ElasticContainer): + """Buildable elastic-container version of a regular gtk.Window. + """ + __gtype_name__ = "ElasticWindow" + + def __init__(self, *args, **kwargs): + gtk.Window.__init__(self, *args, **kwargs) + ElasticContainer.__init__(self) + + +if __name__ == '__main__': + win1 = ElasticWindow() + vbox = gtk.VBox() + ee = ElasticExpander() + ee.set_label("expand (expands window)") + + l1 = gtk.Label("Main content\ngoes here.") + l2 = gtk.Label("Extra content\n\nBlah blah") + vbox.pack_start(l1, True, True) + vbox.pack_start(ee, False, True) + ee.add(l2) + win1.add(vbox) + win1.set_title("elastic test") + win1.connect("destroy", lambda *a: gtk.main_quit()) + win1.show_all() + + gtk.main() + + diff --git a/gui/layout.py b/gui/layout.py index 7516dab..8ee3835 100644 --- a/gui/layout.py +++ b/gui/layout.py @@ -20,6 +20,8 @@ import pango import cairo from gettext import gettext as _ +from elastic import ElasticContainer + class LayoutManager: """Keeps track of tool positions, and main window state. @@ -212,127 +214,6 @@ class LayoutManager: func(*args, **kwargs) -class ElasticContainer: - """Mixin for containers which mirror certain size changes of descendents - - Descendents which wish to report internally-generated size changes should - add the ElasticContent mixin, and should be packed into a container that - derives from ElasticContainer. More than one ElasticContent widget can be - packed under an ElasticContainer, and each can report different types of - resizes - however the sub-hierarchies cannot overlap. You -can- nest - ElasticContainers though: it's the outer one that receives the resize - request. - """ - - def __init__(self): - """Mixin constructor (construct as a gtk.Widget before calling) - """ - self.__last_size = None - self.__saved_size_request = None - - def mirror_elastic_content_resize(self, dx, dy): - """Resize by a given amount. - - This is called by some ElasticContent widget below here in the - hierarchy when it notices a request-size change on itself. - """ - p = self.parent - while p is not None: - if isinstance(p, ElasticContainer): - # propagate up and don't handle here - p.mirror_elastic_content_resize(dx, dy) - return - p = p.parent - self.__saved_size_request = self.get_size_request() - alloc = self.get_allocation() - w = alloc.width+dx - h = alloc.height+dy - if isinstance(self, gtk.Window): - self.resize(w, h) - self.set_size_request(w, h) - self.queue_resize() - - -class ElasticContent: - """Mixin for GTK widgets which want some parent to change size to match. - """ - - def __init__(self, mirror_vertical=True, mirror_horizontal=True): - """Mixin constructor (construct as a gtk.Widget before calling) - - The options control which size changes are reported to the - ElasticContainer ancestor and how: - - `mirror_vertical`: - mirror vertical size changes - - `mirror_horizontal`: - mirror horizontal size changes - - """ - self.__vertical = mirror_vertical - self.__horizontal = mirror_horizontal - if not mirror_horizontal and not mirror_vertical: - return - self.__last_req = None - self.__expose_connid = self.connect_after("expose-event", - self.__after_expose_event) - self.__notify_parent = False - self.connect_after("size-request", self.__after_size_request) - - def __after_expose_event(self, widget, event): - # Begin notifying changes to the ancestor after the first expose event. - # It doesn't matter for widgets that know their size before hand. - # Assume widgets which initially don't know their size *do* know their - # proper size after their first draw, even if they drew themselves - # wrongly and now have to resize and do another size-request... - connid = self.__expose_connid - if not connid: - return - self.__expose_connid = None - self.__notify_parent = True - self.disconnect(connid) - - def __after_size_request(self, widget, req): - # Catch the final value of each size-request, calculate the - # difference needed and throw it back up the widget hierarchy - # to interested parties. - if not self.__last_req: - dx, dy = 0, 0 - else: - w0, h0 = self.__last_req - dx, dy = req.width - w0, req.height - h0 - self.__last_req = (req.width, req.height) - if not self.__notify_parent: - return - p = self.parent - while p is not None: - if isinstance(p, ElasticContainer): - if not self.__vertical: - dy = 0 - if not self.__horizontal: - dx = 0 - if dy != 0 or dx != 0: - p.mirror_elastic_content_resize(dx, dy) - break - if isinstance(p, ElasticContent): - break - p = p.parent - - -class ElasticVBox (gtk.VBox, ElasticContainer): - def __init__(self, *args, **kwargs): - gtk.VBox.__init__(self, *args, **kwargs) - ElasticContainer.__init__(self) - - -class ElasticExpander (gtk.Expander, ElasticContent): - def __init__(self, *args, **kwargs): - gtk.Expander.__init__(self, *args, **kwargs) - ElasticContent.__init__(self, mirror_horizontal=False, - mirror_vertical=True) - - class WindowWithSavedPosition: """Mixin for gtk.Windows which load/save their position via a LayoutManager.