Last active
March 24, 2021 20:40
-
-
Save raitonoberu/0be1c97b63bd84878698150386e77855 to your computer and use it in GitHub Desktop.
Clone of the Fluent UI ProgressRing (pygame)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import pygame | |
import pygame.draw | |
import pygame.locals | |
from math import sin, cos, pi | |
FILLED_COLOR = (108, 88, 123) | |
UNFILLED_COLOR = (204, 204, 204) | |
deg2Rad = (2 * pi) / 360 | |
class ProgressBar(object): | |
def __init__(self, x, y, radius, thickness, low_speed=8, high_speed=12): | |
""" | |
I have to explain what low_speed & high_speed are. | |
These two dots "chase" each other. | |
One moves at a low speed, the other at a high speed. | |
Once the distance between them is 180 degrees (semicircle), | |
they change speeds with each other. | |
8 / 12 is one of the values that works fine. | |
Feel free to play around with it, maybe you will find a better one. | |
""" | |
self.x = x | |
self.y = y | |
self.radius = radius | |
self.thickness = thickness | |
self.speed1 = low_speed | |
self.speed2 = high_speed | |
self.d1 = 0 # degrees of 1st point (0..360) | |
self.d2 = 0 # degrees of 2nd point (0..360) | |
def draw_arc(self, surface): | |
if self.d2 > self.d1: | |
d1, d2 = self.d1, self.d2 | |
else: | |
d2, d1 = self.d1, self.d2 | |
pygame.draw.circle(surface, FILLED_COLOR, self.coords(d1), self.thickness // 2) | |
pygame.draw.arc( | |
surface, | |
FILLED_COLOR, | |
pygame.Rect( | |
self.x - self.radius, | |
self.y - self.radius, | |
self.radius * 2, | |
self.radius * 2, | |
), | |
(90 - d2) * deg2Rad, | |
(90 - d1) * deg2Rad, | |
self.thickness, | |
) | |
pygame.draw.circle(surface, FILLED_COLOR, self.coords(d2), self.thickness // 2) | |
def coords(self, degrees): | |
# returns the coordinates of a point at a certain number of degrees | |
rads = (180 - degrees) * deg2Rad | |
return ( | |
self.x + int(sin(rads) * (self.radius - self.thickness // 2)), | |
self.y + int(cos(rads) * (self.radius - self.thickness // 2)), | |
) | |
def draw(self, surface): | |
# draw a white circle | |
pygame.draw.circle( | |
surface, | |
UNFILLED_COLOR, | |
(self.x, self.y), | |
self.radius, | |
self.thickness, | |
) | |
if self.d1 == self.d2 and self.d1 % 360 == 0: | |
# in the original animation, there is a single frame without an arc. | |
# you can delete it if you want | |
return | |
# draw a filled arc | |
self.draw_arc(surface) | |
def update(self): | |
self.d1 = self.d1 + self.speed1 | |
self.d2 = self.d2 + self.speed2 | |
if self.d1 > 360 and self.d2 > 360: | |
self.d1 -= 360 | |
self.d2 -= 360 | |
if abs(self.d1 - self.d2) >= 180: | |
self.speed1, self.speed2 = self.speed2, self.speed1 | |
if __name__ == "__main__": | |
pygame.init() | |
clock = pygame.time.Clock() | |
display = pygame.display.set_mode((300, 200)) | |
# indetermiate | |
bar = ProgressBar(100, 100, 30, 7) | |
# determinate (just for testing) | |
bar1 = ProgressBar(200, 100, 30, 7) | |
value = 0 # determinate value (0..100) | |
while True: | |
for event in pygame.event.get(): | |
if event.type == pygame.locals.QUIT: | |
pygame.quit() | |
display.fill((255, 255, 255)) | |
# indetermiate | |
bar.update() | |
bar.draw(display) | |
# determinate | |
bar1.d2 = value / 100 * 360 | |
bar1.draw(display) | |
value += 1 | |
if value > 100: | |
value = 0 | |
pygame.display.update() | |
clock.tick(60) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment