From 5d9fdf69adb428c3060e14426b0a539ad770a22d Mon Sep 17 00:00:00 2001 From: Martin Owens Date: Sun, 13 Mar 2022 21:09:20 -0400 Subject: [PATCH] Improve pixmap testing and update clipart extension --- inkex/gui/listview.py | 14 +++-- inkex/gui/pixmap.py | 107 ++++++++++++++++++++------------ other/clipart | 2 +- tests/test_inkex_gui_pixmaps.py | 69 ++++++++++---------- 4 files changed, 111 insertions(+), 81 deletions(-) diff --git a/inkex/gui/listview.py b/inkex/gui/listview.py index 34f448102..56939e721 100644 --- a/inkex/gui/listview.py +++ b/inkex/gui/listview.py @@ -458,13 +458,15 @@ class ViewColumn(object): size - Restrict the images to this size. """ # Manager where icons will be pulled from - pixmaps = pixmaps or PixmapManager("", pixmap_dir="./", size=size) - size = SizeFilter(pixmaps, size=size) if size else None + filters = [SizeFilter] if size else [] + pixmaps = pixmaps or PixmapManager( + "", pixmap_dir="./", filters=filters, size=size + ) renderer = Gtk.CellRendererPixbuf() renderer.set_property("ypad", pad) renderer.set_property("xpad", pad) - func = self.image_func(icon or self.default_icon, pixmaps, size) + func = self.image_func(icon or self.default_icon, pixmaps) return self.add_renderer(renderer, func, expand=False) def add_text_renderer(self, text, wrap=None, template=None): @@ -526,7 +528,7 @@ class ViewColumn(object): return internal - def image_func(self, call, pixmaps=None, size=None): + def image_func(self, call, pixmaps=None): """Wrap, wrap wrap the func""" callout = self.get_callout(call) @@ -539,8 +541,8 @@ class ViewColumn(object): if isinstance(icon or "", str) and pixmaps: # Expect a Gnome theme icon icon = pixmaps.get(icon) - elif icon and size: - icon = size.filter(icon) + elif icon: + icon = pixmaps.apply_filters(icon) cell.set_property("pixbuf", icon) cell.set_property("visible", True) diff --git a/inkex/gui/pixmap.py b/inkex/gui/pixmap.py index f805905c3..02f4ce803 100644 --- a/inkex/gui/pixmap.py +++ b/inkex/gui/pixmap.py @@ -52,15 +52,19 @@ class PixmapFilter: # pylint: disable=too-few-public-methods """ required: List[str] = [] + optional: List[str] = [] - def __init__(self, manager, **kwargs): - self.manager = manager - missing = self.required[:] - for key in kwargs: - if key in missing: - missing.remove(key) - setattr(self, key, kwargs[key]) - self.enabled = len(missing) == 0 + def __init__(self, **kwargs): + self.enabled = True + for key in self.required: + if key not in kwargs: + self.enabled = False + else: + setattr(self, key, kwargs[key]) + + for key in self.optional: + if key in kwargs: + setattr(self, key, kwargs[key]) def filter(self, img, **kwargs): """Run filter, replace this methodwith your own""" @@ -69,6 +73,15 @@ class PixmapFilter: # pylint: disable=too-few-public-methods % type(self).__name__ ) + @staticmethod + def to_size(dat): + """Tries to calculate a size that will work for the data""" + if isinstance(dat, (int, float)): + return (dat, dat) + if isinstance(dat, Iterable) and len(dat) >= 2: + return (dat[0], dat[1]) + return None + class OverlayFilter(PixmapFilter): """Adds an overlay to output images, overlay can be any name that @@ -82,19 +95,27 @@ class OverlayFilter(PixmapFilter): """ + optional = ["position", "overlay", "alpha"] + def __init__(self, *args, **kwargs): self.position = (0, 0) self.overlay = None self.alpha = 255 super().__init__(*args, **kwargs) - self.pad_x, self.pad_y = SizeFilter.to_size(self.position) + self.pad_x, self.pad_y = self.to_size(self.position) def get_overlay(self, **kwargs): - return self.manager.get( - kwargs.get("overlay", None) or self.overlay, exempt=True + if "manager" not in kwargs: + raise ValueError("PixmapManager must be provided when adding an overlay.") + return kwargs["manager"].get( + kwargs.get("overlay", None) or self.overlay, no_overlay=True ) - def filter(self, img, **kwargs): + def filter(self, img, no_overlay=False, **kwargs): + # Recursion protection + if no_overlay: + return img + overlay = self.get_overlay(**kwargs) if overlay: img = img.copy() @@ -128,6 +149,7 @@ class SizeFilter(PixmapFilter): """ required = ["size"] + optional = ["resize_mode"] def __init__(self, *args, **kwargs): self.size = None @@ -135,15 +157,6 @@ class SizeFilter(PixmapFilter): super().__init__(*args, **kwargs) self.img_w, self.img_h = self.to_size(self.size) or (0, 0) - @staticmethod - def to_size(dat): - """Tries to calculate a size that will work for the data""" - if isinstance(dat, (int, float)): - return (dat, dat) - if isinstance(dat, Iterable) and len(dat) >= 2: - return (dat[0], dat[1]) - return None - def aspect(self, img_w, img_h): """Get the aspect ratio of the image resized""" if self.resize_mode == SIZE_STRETCH: @@ -171,6 +184,8 @@ class SizeFilter(PixmapFilter): class PadFilter(SizeFilter): """Add padding to the image to make it a standard size""" + optional = ["padding"] + def __init__(self, *args, **kwargs): self.size = None self.padding = 0.5 @@ -205,7 +220,7 @@ class PixmapManager: default_image = "application-default-icon" icon_theme = ICON_THEME theme_size = 32 - filters = [SizeFilter] + filters: List[type] = [] pixmap_dir = None def __init__(self, location="", **kwargs): @@ -213,16 +228,16 @@ class PixmapManager: if self.pixmap_dir and not os.path.isabs(location): self.location = os.path.join(self.pixmap_dir, location) - self.loader_size = SizeFilter.to_size(kwargs.pop("load_size", None)) - if "size" not in kwargs: - kwargs["size"] = self.theme_size + self.loader_size = PixmapFilter.to_size(kwargs.pop("load_size", None)) # Add any instance specified filters first - self._filters = kwargs.get("filters", []) - for lens in self.filters: - # Now add any class specified filters with optional kwargs - # Default: SizeFiler( size=required_field ) - self._filters.append(lens(self, **kwargs)) + self._filters = [] + for item in kwargs.get("filters", []) + self.filters: + if isinstance(item, PixmapFilter): + self._filters.append(item) + elif callable(item): + # Now add any class specified filters with optional kwargs + self._filters.append(item(**kwargs)) self.cache = {} self.get_pixmap(self.default_image) @@ -231,12 +246,16 @@ class PixmapManager: """Get a pixmap of any kind""" return self.get_pixmap(*args, **kwargs) + def get_missing_image(self): + """Get a missing image when other images aren't found""" + return self.get(self.missing_image) + @staticmethod def data_is_file(data): """Test the file to see if it's a filename or not""" return isinstance(data, str) and "