~fabrixxm/confy

42cddb80a63ce2a7f264bca202742ff6fea7d703 — fabrixxm 8 months ago 732e3a9
Draw bar in EventActionRow

still missing round clipping top and bottom.
1 files changed, 25 insertions(+), 68 deletions(-)

M src/widgets.py
M src/widgets.py => src/widgets.py +25 -68
@@ 29,6 29,9 @@ from gi.repository import Gdk
from gi.repository import Gtk
from gi.repository import GdkPixbuf
from gi.repository import Adw
from gi.repository import Graphene
from gi.repository import Gsk


from .utils import clean_markup, margin
from .models import dbUpdateWatcher


@@ 119,63 122,27 @@ class EventActionRow(Adw.ActionRow):

        self.on_update()

        #Gio.Application.get_default().connect(
        #    "tick", lambda *_: self.queue_draw()
        #)

        #self.connect("draw", self._on_draw)
        Gio.Application.get_default().connect(
            "tick", lambda *_: self.queue_draw()
        )

    def __del__(self):
        if self._hid:
            dbUpdateWatcher.disconnect(self.hid)

    def _roundedclippath(self, cr, x, y, w, h, rtop, rbottom):
        cr.arc(x+rtop, y+rtop, rtop, math.pi, 3*math.pi/2)
        cr.line_to(x+w, y)
        cr.line_to(x+w, y+h)
        cr.line_to(x+w, y+h)
        #cr.arc(x+w-rtop, y+rtop, rtop, 3*math.pi/2, 0) # top-right round corner
        #cr.arc(x+w-rbottom, y+h-rbottom, rbottom, 0, math.pi/2) # bottom-right
        cr.arc(x+rbottom, y+h-rbottom, rbottom, math.pi/2, math.pi)
        cr.close_path()
        cr.clip()

    def _on_draw(self, widget, cr):
        """
        Draw event progress indicator in widget background.
        It's a tick line on left border from top whose lenght is relative to the
        percentage of event time elapsed.

        We need to handle list round corners. Gtk doesn't clip element like HTML
        when rendering with "border-radius" value, so our line will overflow the
        corner.

        I've tried some way to do this:
        -   Drawin a clip path with a rounder corner, getting the rounding from css,
            defining a css rule like "row:first-child { border-top-left-radius: 8px; }"
            but we can't fetch "border-top-left-radius" value via pygobject
            (should be `self.get_style_context().get_property("border-top-left-radius", self.get_style_context().get_state())`
            but we get an exception, I think because it should return a GtkCssValue which pygobject doesn't know)
        -   I tought I could save current style context, add a new class, then render
            the backgrund with `Gtk.render_background()` wich can clip the draw, then
            restore the style context.
            I would then define the style matching the added class defining rounding
            and color, but it doesn't work.

        So now the row get a "first" or "last" class in `pages.BaseListPage.update_list()`.
        Color and corder radii are defined here in code instead of css.
        I use the clip path method. It get a top rounded corner if `self` has "first" class
        and has no header: a list header is rendered before the row itself, thus
        occupying the rounded corner spot. It get a bottom rounded corner if has
        "last" class. The a line of required lenght, color and width is drawn
        from top.
        """
    def _is_first(self):
        return self.get_index() == 0

    def _is_last(self):
        p = self.get_parent()
        if p is None:
            return True
        return p.get_last_child() == self

    def do_snapshot(self, snapshot: Gtk.Snapshot):
        now = datetime.datetime.now(UTC).replace(tzinfo=None)
        obj = self.obj

        totalh = self.get_allocated_height()

        dur = (obj.end.timestamp() - obj.start.timestamp())
        pos = (now.timestamp() - obj.start.timestamp())
        if dur > 0:


@@ 185,28 152,17 @@ class EventActionRow(Adw.ActionRow):
            # set prc to 0 if the event is in the future or 1 if in the past
            prc = int(pos >= 0)

        x = 0
        y = 0
        h = totalh * prc
        w = 10

        # clip at rounded corners
        stylectx = self.get_style_context()
        rtop = 8 if stylectx.has_class("first") and self.get_header() is None else 0
        rbottom = 8 if stylectx.has_class("last") else 0
        x = -2
        y = -2
        w = 4
        h = self.get_allocated_height() * prc

        cr.save()
        # rounded clip path
        self._roundedclippath(cr, x, y-1, w, totalh+2, rtop, rbottom)
        color = self.get_style_context().get_color()
        color.alpha = 0.2
        rect = Graphene.Rect().init(x, y, w, h)
        snapshot.append_color(color, rect)

        # draw line
        cr.set_source_rgba(0,0,0,0.2)
        cr.set_line_width(w)
        cr.move_to(x, y)
        cr.line_to(x, h)
        cr.stroke()

        cr.restore()
        self.snapshot_child(self.get_first_child(), snapshot)

    def on_update(self, *args):
        obj = self.obj


@@ 678,3 634,4 @@ class PageHeaderBar(Gtk.Box):
        self._show_end_title_buttons = v