const { Gtk } = imports.gi; const Lang = imports.lang; import Widget from 'resource:///com/github/Aylur/ags/widget.js' import * as Utils from 'resource:///com/github/Aylur/ags/utils.js' // -- Styling -- // min-height for diameter // min-width for trough stroke // padding for space between trough and progress // margin for space between widget and parent // background-color for trough color // color for progress color // -- Usage -- // font size for progress value (0-100px) (hacky i know, but i want animations) export const AnimatedCircProg = ({ initFrom = 0, initTo = 0, initAnimTime = 2900, initAnimPoints = 1, extraSetup = () => { }, ...rest }) => Widget.DrawingArea({ ...rest, css: `${initFrom != initTo ? 'font-size: ' + initFrom + 'px; transition: ' + initAnimTime + 'ms linear;' : ''}`, setup: (area) => { const styleContext = area.get_style_context(); const width = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL); const height = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL); const padding = styleContext.get_padding(Gtk.StateFlags.NORMAL).left; const marginLeft = styleContext.get_margin(Gtk.StateFlags.NORMAL).left; const marginRight = styleContext.get_margin(Gtk.StateFlags.NORMAL).right; const marginTop = styleContext.get_margin(Gtk.StateFlags.NORMAL).top; const marginBottom = styleContext.get_margin(Gtk.StateFlags.NORMAL).bottom; area.set_size_request(width + marginLeft + marginRight, height + marginTop + marginBottom); area.connect('draw', Lang.bind(area, (area, cr) => { const styleContext = area.get_style_context(); const width = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL); const height = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL); const padding = styleContext.get_padding(Gtk.StateFlags.NORMAL).left; const marginLeft = styleContext.get_margin(Gtk.StateFlags.NORMAL).left; const marginRight = styleContext.get_margin(Gtk.StateFlags.NORMAL).right; const marginTop = styleContext.get_margin(Gtk.StateFlags.NORMAL).top; const marginBottom = styleContext.get_margin(Gtk.StateFlags.NORMAL).bottom; area.set_size_request(width + marginLeft + marginRight, height + marginTop + marginBottom); const progressValue = styleContext.get_property('font-size', Gtk.StateFlags.NORMAL) / 100.0; const bg_stroke = styleContext.get_property('min-width', Gtk.StateFlags.NORMAL); const fg_stroke = bg_stroke - padding; const radius = Math.min(width, height) / 2.0 - Math.max(bg_stroke, fg_stroke) / 2.0; const center_x = width / 2.0 + marginLeft; const center_y = height / 2.0 + marginTop; const start_angle = -Math.PI / 2.0; const end_angle = start_angle + (2 * Math.PI * progressValue); const start_x = center_x + Math.cos(start_angle) * radius; const start_y = center_y + Math.sin(start_angle) * radius; const end_x = center_x + Math.cos(end_angle) * radius; const end_y = center_y + Math.sin(end_angle) * radius; // Draw background const background_color = styleContext.get_property('background-color', Gtk.StateFlags.NORMAL); cr.setSourceRGBA(background_color.red, background_color.green, background_color.blue, background_color.alpha); cr.arc(center_x, center_y, radius, 0, 2 * Math.PI); cr.setLineWidth(bg_stroke); cr.stroke(); if (progressValue == 0) return; // Draw progress const color = styleContext.get_property('color', Gtk.StateFlags.NORMAL); cr.setSourceRGBA(color.red, color.green, color.blue, color.alpha); cr.arc(center_x, center_y, radius, start_angle, end_angle); cr.setLineWidth(fg_stroke); cr.stroke(); // Draw rounded ends for progress arcs cr.setLineWidth(0); cr.arc(start_x, start_y, fg_stroke / 2, 0, 0 - 0.01); cr.fill(); cr.arc(end_x, end_y, fg_stroke / 2, 0, 0 - 0.01); cr.fill(); })); // Init animation if (initFrom != initTo) { area.css = `font-size: ${initFrom}px; transition: ${initAnimTime}ms linear;`; Utils.timeout(20, () => { area.css = `font-size: ${initTo}px;`; }, area) const transitionDistance = initTo - initFrom; const oneStep = initAnimTime / initAnimPoints; area.css = ` font-size: ${initFrom}px; transition: ${oneStep}ms linear; `; for (let i = 0; i < initAnimPoints; i++) { Utils.timeout(Math.max(10, i * oneStep), () => { if(!area) return; area.css = `${initFrom != initTo ? 'font-size: ' + (initFrom + (transitionDistance / initAnimPoints * (i + 1))) + 'px;' : ''}`; }); } } else area.css = 'font-size: 0px;'; extraSetup(area); }, })