Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for spinner-like widget in glimmer-dsl-libui? #20

Closed
rubyFeedback opened this issue Feb 26, 2022 · 1 comment
Closed

Support for spinner-like widget in glimmer-dsl-libui? #20

rubyFeedback opened this issue Feb 26, 2022 · 1 comment

Comments

@rubyFeedback
Copy link

Hey there Andy,

I already wrote a proposal for libui-ng in regards to spinner-widgets.

In ruby-gtk3 the spinner widget can be used to indicate an activity is ongoing.

See here as an example for the spinner in gtk:

https://docs.gtk.org/gtk4/class.Spinner.html

I use this, for example, to a GUI where the user can modify meta-data
of a .mp4 file, via ffmpeg. That part works fine.

Now I was thinking to make this available on windows too. ffmpeg.exe
works on windows, I already know that.

So my idea was to use glimmer-dsl-libui for that. But as far as I am aware
there is no spinner functionality in upstream libui. Would it be possible to
simulate or fake such a spinner widget, in glimmer-dsl-libui?

I don't have a good way to propose this, but two ideas I have on the top
of my head are:

  • Use several images and display them in a rotating manner after a
    specify delay set. This could be a button too but need not necessarily
    be; could be a box container that just shows an image.

or alternatively:

  • Perhaps as a free-drawing canvas that is quite small-ish, like 20px 20px
    or something like that. Then, like every "tick", say 0.3 seconds or something
    like that, it could be redrawn a bit to indicate rotation (activity). This can
    be a super-simple circle too, perhaps perfect-shape allows for partial
    colour fills. Then we could say the upper top right quadrant is red,
    when before it black. Then the lower right quadrant colour is red, and
    the upper top right is now black again, and so forth. So in other words
    to fake a spinner-like widget.

Does not have to look pretty. The main idea behind the spinner is to
indicate to the user that the application is still working, so the user does
not get bored and knows that things are still happening as-is.

I don't know how easy it would be for glimmer-dsl-libui to support it or
whether you think it is useful. The above two points in regards how
to implement it are just examples; perhaps there are more ways to
think about this.

@AndyObtiva
Copy link
Owner

AndyObtiva commented Feb 26, 2022

You can simply implement a spinner with area vector graphics using Glimmer::LibUI::timer.

I added a section to the README called Area Animation that documents how to do it.

Spinner example that has a fully customizable method-based custom control called spinner, which is destroyed if you click on it (you may copy/paste in girb):

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

mac spinner

As you can see, the spinner custom control is fully customizable with options like size (you can set to 20 if you like) and fill_color (which can even be a gradient).

If you click on any of the spinners, they are destroyed. This is how you can remove them in your application once there is no more work to do that needs a spinner, by calling the #destroy method on the area object.

To add them, you simply call code like this (assuming you declared a some_box variable as vertical_box or horizontal_box):

some_box.content { spinner(size: 20) }

BTW, it works on Windows too:

glimmer-dsl-libui-windows-spinner

Also, it works on Linux:

glimmer-dsl-libui-linux-spinner

If there is anything that is not clear enough or you have any further questions, feel free to ask me by replying to this issue (even if closed) or opening a new one if needed.

Cheers!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants