emmental/emmental/buttons.py

115 lines
4.1 KiB
Python

# Copyright 2022 (c) Anna Schumaker.
"""Helper classes for Buttons."""
from gi.repository import GObject
from gi.repository import Gtk
class Button(Gtk.Button):
"""A Gtk.Button with extra properties and default large size."""
icon_name = GObject.Property(type=str)
icon_size = GObject.Property(type=Gtk.IconSize,
default=Gtk.IconSize.NORMAL)
icon_opacity = GObject.Property(type=float, default=1.0,
minimum=0.0, maximum=1.0)
def __init__(self, **kwargs):
"""Initialize a Button."""
super().__init__(focusable=False, **kwargs)
self._image = Gtk.Image(icon_name=self.icon_name,
icon_size=self.icon_size,
opacity=self.icon_opacity)
self.bind_property("icon-name", self._image, "icon-name")
self.bind_property("icon-size", self._image, "icon-size")
self.bind_property("icon-opacity", self._image, "opacity")
self.set_child(self._image)
class PopoverButton(Gtk.MenuButton):
"""A MenuButton with a Gtk.Popover attached."""
popover_child = GObject.Property(type=Gtk.Widget)
def __init__(self, **kwargs):
"""Initialize a popover.Button."""
super().__init__(popover=Gtk.Popover(), **kwargs)
self.bind_property("popover-child", self.get_popover(), "child")
self.get_popover().set_child(self.popover_child)
def popdown(self):
"""Close the popover."""
self.get_popover().popdown()
class SplitButton(Gtk.Box):
"""A Button and secondary widget packed together."""
icon_name = GObject.Property(type=str)
icon_size = GObject.Property(type=Gtk.IconSize,
default=Gtk.IconSize.NORMAL)
def __init__(self, secondary: Gtk.Button, **kwargs):
"""Initialize a Split Button."""
super().__init__(**kwargs)
self._primary = Button(hexpand=True, icon_name=self.icon_name,
icon_size=self.icon_size)
self._separator = Gtk.Separator(orientation=Gtk.Orientation.VERTICAL,
margin_top=12, margin_bottom=12)
self._secondary = secondary
self.bind_property("icon-name", self._primary, "icon-name")
self.bind_property("icon-size", self._primary, "icon-size")
self._primary.connect("clicked", self.__clicked)
self.append(self._primary)
self.append(self._separator)
self.append(secondary)
self.add_css_class("emmental-splitbutton")
def __clicked(self, button: Button) -> None:
self.emit("clicked")
@GObject.Property(type=Gtk.Button, flags=GObject.ParamFlags.READABLE)
def secondary(self) -> Gtk.Button:
"""Get the secondary button attached to the SplitButton."""
return self._secondary
@GObject.Signal
def clicked(self) -> None:
"""Signal that the primary button has been clicked."""
class ImageToggle(Button):
"""Inspired by a ToggleButton, but changes image based on state."""
active_icon_name = GObject.Property(type=str)
inactive_icon_name = GObject.Property(type=str)
def __init__(self, active_icon_name: str, inactive_icon_name: str,
active: bool = False, **kwargs) -> None:
"""Initialize an ImageToggle button."""
super().__init__(active_icon_name=active_icon_name,
inactive_icon_name=inactive_icon_name,
icon_name=inactive_icon_name, active=active, **kwargs)
def do_clicked(self) -> None:
"""Handle a click event."""
self.active = not self.active
@GObject.Property(type=bool, default=False)
def active(self) -> bool:
"""Get the active state."""
return self.icon_name == self.active_icon_name
@active.setter
def active(self, newval: bool) -> None:
if newval != self.active:
icon = self.active_icon_name if newval else self.inactive_icon_name
self.icon_name = icon
self.emit("toggled")
@GObject.Signal
def toggled(self) -> None:
"""Active state has been toggled."""