DEV Community

Cover image for Ruby GUI with Glimmer
Mattias Velamsson
Mattias Velamsson

Posted on

Ruby GUI with Glimmer

From the very first time I started getting into development and programming, I always felt like I wanted to create my very own GUI. Whether it was for something as simple as cheating in a flash game đŸŠčđŸœâ€â™‚ïž or something more useful like setting a timer or calculating expenses, creating an app with an actual interface always interested me. Prior to this I had used PythonAutoGUI and others. However, a couple of weeks ago, I stumbled upon a Ruby library that makes creating a fully functional GUI super easy. Obvisouly, I had to try it out. So in this post, I'll walk through how I used this library to create a simple currency converter.

application preview
Code Walkthrough:
First, install installing and including the glimmer-dsl-libui gem, dotenv gem, and a few other standard libraries for handling URLs, HTTP requests, and JSON parsing. I'm using Dotenv and loading a local .env file in my project holding the API_KEY.

# Requirements
require 'glimmer-dsl-libui'
require 'dotenv'
require 'uri'
require 'net/http'
require 'json'

Dotenv.load
include Glimmer
Enter fullscreen mode Exit fullscreen mode

The next step was to define the currencies and base values I want to work with.

# DATA
currencies = ['USD', 'EUR', 'SEK', 'JPY', 'KRW']
base_values = ['USD', 'EUR', 'SEK', 'JPY', 'KRW']
currencies = currencies.join('%2C%20')

Enter fullscreen mode Exit fullscreen mode

Then I had to make sure to use the above values and create a method that fetches the values of these currencies from my selected API, and then use this data to create items for each currency that includes the symbol, rate and a place holder value of 0. These items are stored in an array, which is returned at the end.

def get_data(currency_array, base)
  data = []
  url = URI("https://api.apilayer.com/exchangerates_data/latest?symbols=#{currency_array}&base=USD")

  https = Net::HTTP.new(url.host, url.port)
  https.use_ssl = true

  request = Net::HTTP::Get.new(url)
  request['apikey'] = ENV['API_KEY']

  response = https.request(request)
  response_hash = JSON.parse(response.body)

  response_hash['rates'].each do |currency, rate|
    item = [currency, rate, 0]
    data.append(item)
  end
  data
end
Enter fullscreen mode Exit fullscreen mode

Now to the main code block. Here we call the get_data method, passing in the currencies array and USD as arguments. This retrieves the updated exchange rate data for the specified currencies relative to USD.

# Fetches the exchange rate for each currency to USD.
updated_data = get_data(currencies, 'USD')
Enter fullscreen mode Exit fullscreen mode

Next, the application window is created using the window method from the glimmer library. I've also named it and set the window dimensions.

Inside the window, we create a vertical box to hold the table and input field, basically like a "grid". The table is created using the table method and consists of three columns: "Currency," "Market Value," and "Converted Value."

Then using the cell_rows method, we pass in the updated_data_array.

window('Currency Converter', 1080, 800) {
  vertical_box {
    table {
      text_column('Currency')
      text_column('Market Value')
      text_column('Converted Value')

       cell_rows updated_data
    }
#...
Enter fullscreen mode Exit fullscreen mode

On the bottom of the app, I added an input field using the search_entry method. This input field enter a value to convert.

The stretch false is pretty much just a bool telling the input field not to stretch vertically.

 # Input Field
    search_entry { |value|
      stretchy false
#...
Enter fullscreen mode Exit fullscreen mode

To make the input field "responsive" to changes, I defined a on_changed block. In short the block takes the value in the input field, and copies the data array and replaces it with an updated one.

 # Action on input
      on_changed do
        new_value = value.text
        new_data ||= updated_data.dup
#...
Enter fullscreen mode Exit fullscreen mode

We then iterate over each currency item in new_data and update the converted value based on the new input. The converted value is calculated and rounded to two decimals. The updated values are then stored back in the new_data array, which is rendered in the app.

# Iterates over each of the currencies added, and replaces the default "0" with the actual value.
        new_data.each do |currency|
          currency[2] = 0
          new_total = (currency[2]) + new_value.to_i * currency[1]
          currency[2] = new_total.round(2)
        end
      end
    }
  }
}.show
Enter fullscreen mode Exit fullscreen mode

That's all there is to it really. It was fun trying a completely new library that I had no previous experience of, or heard about before and just figuring things out using the provided documentation.

You can find the full code here.

Top comments (2)

Collapse
 
daddie888 profile image
daddie888

Hi, I'm a user of glimmer-dsl-libui but one thing that bothers me is that in a table it is not possible to set the width of the columns in code, you can adjust by hand but that is not what I want. Same thing when I run your code. In your demo the width is adjusted to the witdh of the data, is this recorded after the manual adjustment or is this because you use a Mac ? (I'm on Windows)

Collapse
 
smackdh profile image
Mattias Velamsson

Hi,

You can nest your horizontal and vertical rows to make it position itself as you'd like, and you can also set them to be "stretchy" or not.

I've only tried running the app on WSL Linux / macOS so if you are experiencing different sizing on Windows I'm afraid I don't have any good answer for that.

Other than this I think that the positioning and resizing of the columns is unfortunately not available in the APIs of the library yet.