Sunday, February 27, 2022

Glimmer DSL for LibUI Progress Spinner

I received a GitHub issue request the other day asking how to implement a progress spinner in Glimmer DSL for LibUI. I did a quick implementation of it using `area` vector graphics, and documented it under the newly added Area Animation section in the README.

The solution is as simple as drawing a donut shape with multiple overlapping circles, and then adding an arc that covers part of the donut shape in order to show a filled area rotating around as a progress spinner. The rotation is repeated regularly using the `Glimmer::LibUI::timer` method.

Of course, it was encapsulated into a fully customizable custom control (aka custom widget) called `spinner` by using a combination of the method-based custom keyword and area-based custom control approaches. 


Code:

# From: https://github.com/AndyObtiva/glimmer-dsl-libui#area-animation
require 'glimmer-dsl-libui'
class SpinnerExample
include Glimmer
SIZE = 120
def initialize
create_gui
end
def launch
@main_window.show
end
def create_gui
@main_window = window {
title 'Spinner'
content_size SIZE*2, SIZE*2
horizontal_box {
padded false
vertical_box {
padded false
spinner(size: SIZE)
spinner(size: SIZE, fill_color: [42, 153, 214])
}
vertical_box {
padded false
spinner(size: SIZE/2.0, fill_color: :orange)
spinner(size: SIZE/2.0, fill_color: {x0: 0, y0: 0, x1: SIZE/2.0, y1: SIZE/2.0, stops: [{pos: 0.25, r: 204, g: 102, b: 204}, {pos: 1, r: 2, g: 2, b: 254}]})
spinner(size: SIZE/2.0, fill_color: :green, unfilled_color: :yellow)
spinner(size: SIZE/2.0, fill_color: :white, unfilled_color: :gray, background_color: :black)
}
}
}
end
def spinner(size: 40.0, fill_color: :gray, background_color: :white, unfilled_color: {r: 243, g: 243, b: 243}, donut_percentage: 0.25)
arc1 = arc2 = nil
area { |the_area|
rectangle(0, 0, size, size) {
fill background_color
}
circle(size/2.0, size/2.0, size/2.0) {
fill fill_color
}
arc1 = arc(size/2.0, size/2.0, size/2.0, 0, 180) {
fill unfilled_color
}
arc2 = arc(size/2.0, size/2.0, size/2.0, 90, 180) {
fill unfilled_color
}
circle(size/2.0, size/2.0, (size/2.0)*(1.0 - donut_percentage)) {
fill background_color
}
on_mouse_up do
the_area.destroy
end
}.tap do
Glimmer::LibUI.timer(0.05) do
delta = 10
arc1.start_angle += delta
arc2.start_angle += delta
end
end
end
end
SpinnerExample.new.launch

Happy Glimmering!

No comments: