DEV Community

Cover image for Glimmer DSL for SWT Canvas Path DSL
Andy Maleh
Andy Maleh

Posted on

Glimmer DSL for SWT Canvas Path DSL

Glimmer DSL for SWT had a relatively major release in v4.18.6.0 and its follow-up v4.18.6.1 to introduce a new Sub-DSL called the Canvas Path DSL, which enables creating paths consisting of the following:

  • Points
  • Lines
  • Quadratic Bezier Curves
  • Cubic Bezier Curves

Unlike other imperative graphing GUI libraries, Glimmer facilitates declarative creation of paths. In other words, it requires no explicit use of move_to, curve_to, etc... (even if possible directly via SWT), yet clear and concise declaration of paths via nouns instead, such as path, point, line, quad, and cubic, thus enabling higher code understandability, maintainability, and productivity.

# From: https://github.com/AndyObtiva/glimmer-dsl-swt/blob/development/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#canvas-path-dsl require 'glimmer-dsl-swt' include Glimmer shell { text 'Canvas Path Example' minimum_size 300, 300 canvas { path { foreground :black 250.times {|n| cubic(n + n%30, n+ n%50, 40, 40, 70, 70, n + 20 + n%30, n%30*-1 * n%50) } } } }.open 
Enter fullscreen mode Exit fullscreen mode

Example

In fact, two new samples have been added to Glimmer DSL for SWT to demo the new Canvas Path DSL capabilities.

Hello, Canvas Path!

Hello Canvas Path

# From: https://github.com/AndyObtiva/glimmer-dsl-swt/blob/development/docs/reference/GLIMMER_SAMPLES.md#hello-canvas-path require 'glimmer-dsl-swt' include Glimmer shell { text 'Hello, Canvas Path!' minimum_size 800, 700 background :white canvas { background :white text('line', 15, 200) { foreground :red } @path1 = path { antialias :on foreground :red } text('quad', 15, 300) { foreground :dark_green } @path2 = path { antialias :on foreground :dark_green } text('cubic', 15, 400) { foreground :blue } @path3 = path { antialias :on foreground :blue } } on_swt_show { Thread.new { y1 = y2 = y3 = 300 800.times.each do |x| x += 55 x1 = x - 2 x2 = x - 1 x3 = x y1 = y3 y2 = y1 y3 = [[y3 + (rand*24 - 12), 0].max, 700].min @path1.content { line(x1, y1 - 100) } if x % 2 == 0 @path2.content { quad(x1, y1, x2, y2) } end if x % 3 == 0 @path3.content { cubic(x1, y1 + 100, x2, y2 + 100, x3, y3 + 100) } end sleep(0.01) end } } }.open 
Enter fullscreen mode Exit fullscreen mode

Stock Ticker

Stock Ticker

# From: https://github.com/AndyObtiva/glimmer-dsl-swt/blob/development/docs/reference/GLIMMER_SAMPLES.md#stock-ticker require 'glimmer-dsl-swt' # This Sample is an Early Alpha (New Canvas Path DSL Feature) class StockTicker class Stock class << self attr_writer :stock_price_min, :stock_price_max def stock_price_min @stock_price_min ||= 1 end def stock_price_max @stock_price_max ||= 600 end end attr_reader :name, :stock_prices attr_accessor :stock_price def initialize(name, stock_price) @name = name @stock_price = stock_price @stock_prices = [@stock_price] @delta_sign = 1 start_new_trend! end def tick! @tick_count = @tick_count.to_i + 1 delta = @tick_count%@trend_length if delta == 0 @delta_sign *= -1 start_new_trend! end stock_prices << self.stock_price = [[@stock_price + @delta_sign*delta, Stock.stock_price_min].max, Stock.stock_price_max].min end def start_new_trend! @trend_length = (rand*12).to_i + 1 end end include Glimmer::UI::CustomShell before_body { @stocks = [ Stock.new('DELL', 81), Stock.new('AAPL', 121), Stock.new('MSFT', 232), Stock.new('ADBE', 459), ] @stock_colors = [:red, :dark_green, :blue, :dark_magenta] max_stock_name_width = 0 left_margin = 5 @tabs = ['Lines', 'Quadratic Bezier Curves', 'Cubic Bezier Curves', 'Points'].map {|title| {title: title, stock_paths: [], stock_transforms: []}} @stocks.each_with_index do |stock, stock_index| observe(stock, :stock_price) do |new_price| begin @tabs.each do |tab| new_x = stock.stock_prices.count - 1 new_y = @tabs.first[:canvas].bounds.height - new_price - 1 max_stock_name_width = tab[:text]&.bounds&.width if tab[:text]&.bounds&.width.to_f > max_stock_name_width if new_x > 0 case tab[:title] when 'Cubic Bezier Curves' if new_x%3 == 0 && stock.stock_prices[new_x] && stock.stock_prices[new_x - 1] && stock.stock_prices[new_x - 2] tab[:stock_paths][stock_index].content { cubic(new_x - 2, @tabs.first[:canvas].bounds.height - stock.stock_prices[new_x - 2] - 1, new_x - 1, @tabs.first[:canvas].bounds.height - stock.stock_prices[new_x - 1] - 1, new_x, new_y) tab[:stock_transforms][stock_index] ||= transform { translate max_stock_name_width + 5 + left_margin, tab[:text].bounds.height / 2.0 } } end when 'Quadratic Bezier Curves' if new_x%2 == 0 && stock.stock_prices[new_x] && stock.stock_prices[new_x - 1] tab[:stock_paths][stock_index].content { quad(new_x - 1, @tabs.first[:canvas].bounds.height - stock.stock_prices[new_x - 1] - 1, new_x, new_y) tab[:stock_transforms][stock_index] ||= transform { translate max_stock_name_width + 5 + left_margin, tab[:text].bounds.height / 2.0 } } end when 'Lines' tab[:stock_paths][stock_index].content { line(new_x, new_y) tab[:stock_transforms][stock_index] ||= transform { translate max_stock_name_width + 5 + left_margin, tab[:text].bounds.height / 2.0 } } when 'Points' tab[:stock_paths][stock_index].content { point(new_x, new_y) tab[:stock_transforms][stock_index] ||= transform { translate max_stock_name_width + 5 + left_margin, tab[:text].bounds.height / 2.0 } } end new_x_location = new_x + max_stock_name_width + 5 + left_margin + 5 canvas_width = tab[:canvas].bounds.width if new_x_location > canvas_width tab[:canvas].set_size(new_x_location, @tabs.first[:canvas].bounds.height) tab[:canvas].cursor = :hand tab[:scrolled_composite].set_min_size(new_x_location, @tabs.first[:canvas].bounds.height) tab[:scrolled_composite].set_origin(tab[:scrolled_composite].origin.x + 1, tab[:scrolled_composite].origin.y) if (tab[:scrolled_composite].origin.x + tab[:scrolled_composite].client_area.width) == canvas_width end else tab[:canvas].content { tab[:text] = text(stock.name, new_x + left_margin, new_y) { foreground @stock_colors[stock_index] } } end end rescue => e Glimmer::Config.logger.error {e.full_message} end end end } after_body { @thread = Thread.new { loop { @stocks.each(&:tick!) sleep(0.01) } } } body { shell { fill_layout { margin_width 15 margin_height 15 } text 'Stock Ticker' minimum_size 650, 650 background :white @tab_folder = tab_folder { @tabs.each do |tab| tab_item { fill_layout { margin_width 0 margin_height 0 } text tab[:title] tab[:scrolled_composite] = scrolled_composite { tab[:canvas] = canvas { background :white @stocks.count.times do |stock_index| tab[:stock_paths][stock_index] = path { antialias :on foreground @stock_colors[stock_index] } end on_mouse_down { @drag_detected = false } on_drag_detected { |drag_detect_event| @drag_detected = true @drag_start_x = drag_detect_event.x @drag_start_y = drag_detect_event.y } on_mouse_move { |mouse_event| if @drag_detected origin = tab[:scrolled_composite].origin new_x = origin.x - (mouse_event.x - @drag_start_x) new_y = origin.y - (mouse_event.y - @drag_start_y) tab[:scrolled_composite].set_origin(new_x, new_y) end } on_mouse_up { |mouse_event| @drag_detected = false } } } } end } on_swt_show { Stock.stock_price_min = 25 Stock.stock_price_max = @tabs.first[:canvas].bounds.height - 6 # pre-initialize all tabs by selecting them so that they render content when they are later in the background @tab_folder.items.each do |item| @tab_folder.selection = item end @tab_folder.selection = @tab_folder.items.first } on_widget_disposed { @thread.kill # safe to kill as data is in memory only } } } end StockTicker.launch 
Enter fullscreen mode Exit fullscreen mode

There is nothing more productive than Glimmer DSL for SWT when it comes to building cross-platform desktop applications, bar none! And, it is only getting better every day. Start learning Glimmer DSL for SWT today by reading Glimmer blog posts and building your own apps while reporting feedback for improvement. It is about time Ruby's become the world leading language for desktop development, not just web.

Happy Glimmering!

Top comments (0)