Skip to content

Instantly share code, notes, and snippets.

@benreu
Created January 27, 2020 02:05
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save benreu/18dea8afc7c2ce75aae5297f6096d657 to your computer and use it in GitHub Desktop.
Save benreu/18dea8afc7c2ce75aae5297f6096d657 to your computer and use it in GitHub Desktop.
A circular progress bar in Python based on phastmike's Vala widget
#!/usr/bin/env python
#
# pygtk-circular-progress.py
# based on https://github.com/phastmike/vala-circular-progress-bar
# Copyright (C) 2020 Reuben pygtk.posting@gmail.com
#
# pygtk-circular-progress 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 3 of the License, or
# (at your option) any later version.
#
# pygtk-circular-progress is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
import cairo
import gi
gi.require_version("Gtk", "3.0")
gi.require_version('PangoCairo', '1.0')
from gi.repository import Gtk, Gdk, GObject, Pango, PangoCairo
import os, sys, math
class CircularProgressBar (Gtk.Bin):
min_diameter = 80
line_width = 1
percentage = 0
center_fill_color = "#adadad"
radius_fill_color = "#d3d3d3"
progress_fill_color = "#4a90d9"
center_filled = False
radius_filled = False
font = "URW Gothic"
line_cap = cairo.LineCap.BUTT
def __init__ (self):
Gtk.Bin.__init__(self)
def calculate_radius (self) :
width = float(self.get_allocated_width ()) / 2
height = (float(self.get_allocated_height ()) / 2) - 1
return int(min(width, height))
def calculate_diameter (self) :
return 2 * self.calculate_radius ()
def do_get_request_mode (self) :
return Gtk.SizeRequestMode.CONSTANT_SIZE
def do_get_preferred_width (self) :
d = self.calculate_diameter ()
min_w = self.min_diameter
if d > self.min_diameter :
natural_w = d
else :
natural_w = self.min_diameter
return d, natural_w
def do_get_preferred_height (self) :
d = self.calculate_diameter ()
min_h = self.min_diameter
if d > self.min_diameter :
natural_h = d
else :
natural_h = self.min_diameter
return d, natural_h
def do_draw (self, cr) :
w = h = 0
delta = 0
color = Gdk.RGBA ()
layout = PangoCairo.create_layout (cr)
desc = Pango.FontDescription()
cr.save ()
color = Gdk.RGBA ()
center_x = self.get_allocated_width () / 2
center_y = self.get_allocated_height () / 2
radius = self.calculate_radius ()
d = radius - self.line_width
delta = radius - self.line_width / 2
if d < 0 :
delta = 0
self.line_width = radius
color = Gdk.RGBA ()
cr.set_line_cap (self.line_cap)
cr.set_line_width (self.line_width)
# Center Fill
if self.center_filled == True:
cr.arc (center_x, center_y, delta, 0, 2 * math.pi)
color.parse (self.center_fill_color)
Gdk.cairo_set_source_rgba (cr, color)
cr.fill ()
# Radius Fill
if self.radius_filled == True:
cr.arc (center_x, center_y, delta, 0, 2 * math.pi)
color.parse (self.radius_fill_color)
Gdk.cairo_set_source_rgba (cr, color)
cr.stroke ()
# Progress Fill
progress = float(self.percentage)
if progress > 0:
cr.arc (center_x,
center_y,
delta,
1.5 * math.pi,
(1.5 + progress * 2 ) * math.pi)
color.parse (self.progress_fill_color)
Gdk.cairo_set_source_rgba (cr, color)
cr.stroke ()
# Textual information
context = self.get_style_context ()
context.save ()
context.add_class (Gtk.STYLE_CLASS_TROUGH)
color = context.get_color (context.get_state ())
Gdk.cairo_set_source_rgba (cr, color)
# Percentage
layout = PangoCairo.create_layout (cr)
layout.set_text (str(int(self.percentage * 100.0)), -1)
desc = Pango.FontDescription.from_string (self.font + " 24")
layout.set_font_description (desc)
PangoCairo.update_layout (cr, layout)
w, h = layout.get_size ()
cr.move_to (center_x - ((w / Pango.SCALE) / 2), center_y - 27 )
PangoCairo.show_layout (cr, layout)
# Units indicator ('PERCENT')
layout.set_text ("PERCENT", -1)
desc = Pango.FontDescription.from_string (self.font + " 8")
layout.set_font_description (desc)
PangoCairo.update_layout (cr, layout)
w, h = layout.get_size ()
cr.move_to (center_x - ((w / Pango.SCALE) / 2), center_y + 13)
PangoCairo.show_layout (cr, layout)
context.restore ()
cr.restore ()
GObject.type_register(CircularProgressBar)
class GUI (Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self)
pb = CircularProgressBar()
# have a peek at line 32-41 for all settings
pb.percentage = .38
pb.line_width = 3
pb.radius_filled = True
pb.center_filled = True
self.connect('destroy', self.on_window_destroy)
self.add(pb)
self.show_all()
def on_window_destroy(self, window):
Gtk.main_quit()
def main():
app = GUI()
Gtk.main()
if __name__ == "__main__":
sys.exit(main())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment