DEV Community

Cover image for Glimmer DSL for SWT Hello, Canvas Data-Binding! (+ Quad & Cubic)
Andy Maleh
Andy Maleh

Posted on • Updated on

Glimmer DSL for SWT Hello, Canvas Data-Binding! (+ Quad & Cubic)

Glimmer DSL for SWT v4.24.0.2 has been released with the following changes:

  • Extend Hello, Canvas Data-Binding! to support editing a quadratic Bézier curve and a cubic Bézier curve, and Drag & Drop of endpoints / control points
  • Fix issue with data-binding quad & cubic path shape point_array

Below are the updated Hello, Canvas Data-Binding! sample animated screenshot, code, and video tutorial.

Updated Hello, Canvas Data-Binding! Video Demo:

hello canvas data binding video

Updated Hello, Canvas Data-Binding! Code:

require 'glimmer-dsl-swt'

class HelloCanvasDataBinding
  class PathShape
    attr_accessor :foreground_red, :foreground_green, :foreground_blue, :line_width_value, :line_style_value

    def foreground_value
      [foreground_red, foreground_green, foreground_blue]
    end

    def line_style_value_options
      [:solid, :dash, :dot, :dashdot, :dashdotdot]
    end
  end

  class LinePathShape < PathShape
    attr_accessor :x1_value, :y1_value, :x2_value, :y2_value
  end

  class QuadPathShape < PathShape
    attr_accessor :x1_value, :y1_value, :cx_value, :cy_value, :x2_value, :y2_value

    def point_array
      [x1_value, y1_value, cx_value, cy_value, x2_value, y2_value]
    end
  end

  class CubicPathShape < PathShape
    attr_accessor :x1_value, :y1_value, :cx1_value, :cy1_value, :cx2_value, :cy2_value, :x2_value, :y2_value

    def point_array
      [x1_value, y1_value, cx1_value, cy1_value, cx2_value, cy2_value, x2_value, y2_value]
    end
  end

  include Glimmer::GUI::Application # alias for Glimmer::UI::CustomShell / Glimmer::UI::CustomWindow

  CANVAS_WIDTH  = 300
  CANVAS_HEIGHT = 300

  before_body do
    @line = LinePathShape.new
    @line.x1_value = 5
    @line.y1_value = 5
    @line.x2_value = CANVAS_WIDTH - 5
    @line.y2_value = CANVAS_HEIGHT - 5
    @line.foreground_red = 28
    @line.foreground_green = 128
    @line.foreground_blue = 228
    @line.line_width_value = 3
    @line.line_style_value = :dash

    @quad = QuadPathShape.new
    @quad.x1_value = 5
    @quad.y1_value = CANVAS_HEIGHT - 5
    @quad.cx_value = (CANVAS_WIDTH - 10)/2.0
    @quad.cy_value = 5
    @quad.x2_value = CANVAS_WIDTH - 5
    @quad.y2_value = CANVAS_HEIGHT - 5
    @quad.foreground_red = 28
    @quad.foreground_green = 128
    @quad.foreground_blue = 228
    @quad.line_width_value = 3
    @quad.line_style_value = :dot

    @cubic = CubicPathShape.new
    @cubic.x1_value = 5
    @cubic.y1_value = (CANVAS_WIDTH - 10)/2.0
    @cubic.cx1_value = (CANVAS_WIDTH - 10)*0.25
    @cubic.cy1_value = (CANVAS_WIDTH - 10)*0.25
    @cubic.cx2_value = (CANVAS_WIDTH - 10)*0.75
    @cubic.cy2_value = (CANVAS_WIDTH - 10)*0.75
    @cubic.x2_value = CANVAS_WIDTH - 5
    @cubic.y2_value = (CANVAS_WIDTH - 10)/2.0
    @cubic.foreground_red = 28
    @cubic.foreground_green = 128
    @cubic.foreground_blue = 228
    @cubic.line_width_value = 3
    @cubic.line_style_value = :dashdot
  end

  body {
    shell(:no_resize) {
      text 'Hello, Canvas Data-Binding!'

      tab_folder {
        tab_item {
          grid_layout(6, true) {
            margin_width 0
            margin_height 0
            horizontal_spacing 0
            vertical_spacing 0
          }
          text 'Line'

          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            text 'x1'
          }
          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            text 'y1'
          }

          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            maximum CANVAS_WIDTH
            increment 3
            selection <=> [@line, :x1_value]
          }
          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            maximum CANVAS_HEIGHT
            increment 3
            selection <=> [@line, :y1_value]
          }

          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            text 'x2'
          }
          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            text 'y2'
          }

          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            maximum CANVAS_WIDTH
            increment 3
            selection <=> [@line, :x2_value]
          }
          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            maximum CANVAS_HEIGHT
            increment 3
            selection <=> [@line, :y2_value]
          }

          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 2
            }
            text 'foreground red'
          }
          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 2
            }
            text 'foreground green'
          }
          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 2
            }
            text 'foreground blue'
          }

          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 2
            }
            maximum 255
            increment 10
            selection <=> [@line, :foreground_red]
          }
          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 2
            }
            maximum 255
            increment 10
            selection <=> [@line, :foreground_green]
          }
          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 2
            }
            maximum 255
            increment 10
            selection <=> [@line, :foreground_blue]
          }

          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            text 'line width'
          }
          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            text 'line style'
          }

          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            maximum 255
            selection <=> [@line, :line_width_value]
          }
          combo(:read_only) {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            selection <=> [@line, :line_style_value]
          }

          @line_canvas = canvas {
            layout_data(:center, :center, false, false) {
              horizontal_span 6
              width_hint CANVAS_WIDTH
              height_hint CANVAS_WIDTH
            }

            background :white

            line {
              x1         <= [@line, :x1_value]
              y1         <= [@line, :y1_value]
              x2         <= [@line, :x2_value]
              y2         <= [@line, :y2_value]
              foreground <= [@line, :foreground_value, computed_by: [:foreground_red, :foreground_green, :foreground_blue]]
              line_width <= [@line, :line_width_value]
              line_style <= [@line, :line_style_value]
            }

            @line_oval1 = oval {
              x          <= [@line, :x1_value, on_read: ->(val) {val - 5}]
              y          <= [@line, :y1_value, on_read: ->(val) {val - 5}]
              width 10
              height 10
              background :black
            }

            @line_oval2 = oval {
              x          <= [@line, :x2_value, on_read: ->(val) {val - 5}]
              y          <= [@line, :y2_value, on_read: ->(val) {val - 5}]
              width 10
              height 10
              background :black
            }

            on_mouse_down do |mouse_event|
              @selected_shape = @line_canvas.shape_at_location(mouse_event.x, mouse_event.y)
              @selected_shape = nil unless @selected_shape.is_a?(Glimmer::SWT::Custom::Shape::Oval)
              @line_canvas.cursor = :hand if @selected_shape
            end

            on_drag_detected do |drag_detect_event|
              @drag_detected = true
              @drag_current_x = drag_detect_event.x
              @drag_current_y = drag_detect_event.y
            end

            on_mouse_move do |mouse_event|
              if @drag_detected && @selected_shape
                delta_x = mouse_event.x - @drag_current_x
                delta_y = mouse_event.y - @drag_current_y
                case @selected_shape
                when @line_oval1
                  @line.x1_value += delta_x
                  @line.y1_value += delta_y
                when @line_oval2
                  @line.x2_value += delta_x
                  @line.y2_value += delta_y
                end
                @drag_current_x = mouse_event.x
                @drag_current_y = mouse_event.y
              end
            end

            on_mouse_up do |mouse_event|
              @line_canvas.cursor = :arrow
              @drag_detected = false
              @selected_shape = nil
            end
          }
        }

        tab_item {
          grid_layout(6, true) {
            margin_width 0
            margin_height 0
            horizontal_spacing 0
            vertical_spacing 0
          }
          text 'Quad'

          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            text 'x1'
          }
          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            text 'y1'
          }

          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            maximum CANVAS_WIDTH
            increment 3
            selection <=> [@quad, :x1_value]
          }
          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            maximum CANVAS_HEIGHT
            increment 3
            selection <=> [@quad, :y1_value]
          }

          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            text 'control x'
          }
          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            text 'control y'
          }

          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            maximum CANVAS_WIDTH
            increment 3
            selection <=> [@quad, :cx_value]
          }
          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            maximum CANVAS_HEIGHT
            increment 3
            selection <=> [@quad, :cy_value]
          }

          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            text 'x2'
          }
          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            text 'y2'
          }

          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            maximum CANVAS_WIDTH
            increment 3
            selection <=> [@quad, :x2_value]
          }
          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            maximum CANVAS_HEIGHT
            increment 3
            selection <=> [@quad, :y2_value]
          }

          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 2
            }
            text 'foreground red'
          }
          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 2
            }
            text 'foreground green'
          }
          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 2
            }
            text 'foreground blue'
          }

          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 2
            }
            maximum 255
            increment 10
            selection <=> [@quad, :foreground_red]
          }
          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 2
            }
            maximum 255
            increment 10
            selection <=> [@quad, :foreground_green]
          }
          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 2
            }
            maximum 255
            increment 10
            selection <=> [@quad, :foreground_blue]
          }

          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            text 'line width'
          }
          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            text 'line style'
          }

          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            maximum 255
            selection <=> [@quad, :line_width_value]
          }
          combo(:read_only) {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            selection <=> [@quad, :line_style_value]
          }

          @quad_canvas = canvas {
            layout_data(:center, :center, false, false) {
              horizontal_span 6
              width_hint CANVAS_WIDTH
              height_hint CANVAS_WIDTH
            }

            background :white

            path {
              foreground  <= [@quad, :foreground_value, computed_by: [:foreground_red, :foreground_green, :foreground_blue]]
              line_width  <= [@quad, :line_width_value]
              line_style  <= [@quad, :line_style_value]

              quad {
                point_array <= [@quad, :point_array, computed_by: [:x1_value, :y1_value, :cx_value, :cy_value, :x2_value, :y2_value]]
              }
            }

            @quad_oval1 = oval {
              x          <= [@quad, :x1_value, on_read: ->(val) {val - 5}]
              y          <= [@quad, :y1_value, on_read: ->(val) {val - 5}]
              width 10
              height 10
              background :black
            }

            @quad_oval2 = oval {
              x          <= [@quad, :cx_value, on_read: ->(val) {val - 5}]
              y          <= [@quad, :cy_value, on_read: ->(val) {val - 5}]
              width 10
              height 10
              background :dark_gray
            }

            @quad_oval3 = oval {
              x          <= [@quad, :x2_value, on_read: ->(val) {val - 5}]
              y          <= [@quad, :y2_value, on_read: ->(val) {val - 5}]
              width 10
              height 10
              background :black
            }

            on_mouse_down do |mouse_event|
              @selected_shape = @quad_canvas.shape_at_location(mouse_event.x, mouse_event.y)
              @selected_shape = nil unless @selected_shape.is_a?(Glimmer::SWT::Custom::Shape::Oval)
              @quad_canvas.cursor = :hand if @selected_shape
            end

            on_drag_detected do |drag_detect_event|
              @drag_detected = true
              @drag_current_x = drag_detect_event.x
              @drag_current_y = drag_detect_event.y
            end

            on_mouse_move do |mouse_event|
              if @drag_detected && @selected_shape
                delta_x = mouse_event.x - @drag_current_x
                delta_y = mouse_event.y - @drag_current_y
                case @selected_shape
                when @quad_oval1
                  @quad.x1_value += delta_x
                  @quad.y1_value += delta_y
                when @quad_oval2
                  @quad.cx_value += delta_x
                  @quad.cy_value += delta_y
                when @quad_oval3
                  @quad.x2_value += delta_x
                  @quad.y2_value += delta_y
                end
                @drag_current_x = mouse_event.x
                @drag_current_y = mouse_event.y
              end
            end

            on_mouse_up do |mouse_event|
              @quad_canvas.cursor = :arrow
              @drag_detected = false
              @selected_shape = nil
            end
          }
        }

        tab_item {
          grid_layout(6, true) {
            margin_width 0
            margin_height 0
            horizontal_spacing 0
            vertical_spacing 0
          }
          text 'Cubic'

          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            text 'x1'
          }
          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            text 'y1'
          }

          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            maximum CANVAS_WIDTH
            increment 3
            selection <=> [@cubic, :x1_value]
          }
          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            maximum CANVAS_HEIGHT
            increment 3
            selection <=> [@cubic, :y1_value]
          }

          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            text 'control 1 x'
          }
          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            text 'control 1 y'
          }

          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            maximum CANVAS_WIDTH
            increment 3
            selection <=> [@cubic, :cx1_value]
          }
          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            maximum CANVAS_HEIGHT
            increment 3
            selection <=> [@cubic, :cy1_value]
          }

          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            text 'control 2 x'
          }
          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            text 'control 2 y'
          }

          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            maximum CANVAS_WIDTH
            increment 3
            selection <=> [@cubic, :cx2_value]
          }
          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            maximum CANVAS_HEIGHT
            increment 3
            selection <=> [@cubic, :cy2_value]
          }

          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            text 'x2'
          }
          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            text 'y2'
          }

          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            maximum CANVAS_WIDTH
            increment 3
            selection <=> [@cubic, :x2_value]
          }
          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            maximum CANVAS_HEIGHT
            increment 3
            selection <=> [@cubic, :y2_value]
          }

          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 2
            }
            text 'foreground red'
          }
          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 2
            }
            text 'foreground green'
          }
          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 2
            }
            text 'foreground blue'
          }

          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 2
            }
            maximum 255
            increment 10
            selection <=> [@cubic, :foreground_red]
          }
          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 2
            }
            maximum 255
            increment 10
            selection <=> [@cubic, :foreground_green]
          }
          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 2
            }
            maximum 255
            increment 10
            selection <=> [@cubic, :foreground_blue]
          }

          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            text 'line width'
          }
          label {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            text 'line style'
          }

          spinner {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            maximum 255
            selection <=> [@cubic, :line_width_value]
          }
          combo(:read_only) {
            layout_data(:fill, :center, false, false) {
              horizontal_span 3
            }
            selection <=> [@cubic, :line_style_value]
          }

          @cubic_canvas = canvas {
            layout_data(:center, :center, false, false) {
              horizontal_span 6
              width_hint CANVAS_WIDTH
              height_hint CANVAS_WIDTH
            }

            background :white

            path {
              foreground  <= [@cubic, :foreground_value, computed_by: [:foreground_red, :foreground_green, :foreground_blue]]
              line_width  <= [@cubic, :line_width_value]
              line_style  <= [@cubic, :line_style_value]

              cubic {
                point_array <= [@cubic, :point_array, computed_by: [:x1_value, :y1_value, :cx1_value, :cy1_value, :cx2_value, :cy2_value, :x2_value, :y2_value]]
              }
            }

            @cubic_oval1 = oval {
              x          <= [@cubic, :x1_value, on_read: ->(val) {val - 5}]
              y          <= [@cubic, :y1_value, on_read: ->(val) {val - 5}]
              width 10
              height 10
              background :black
            }

            @cubic_oval2 = oval {
              x          <= [@cubic, :cx1_value, on_read: ->(val) {val - 5}]
              y          <= [@cubic, :cy1_value, on_read: ->(val) {val - 5}]
              width 10
              height 10
              background :dark_gray
            }

            @cubic_oval3 = oval {
              x          <= [@cubic, :cx2_value, on_read: ->(val) {val - 5}]
              y          <= [@cubic, :cy2_value, on_read: ->(val) {val - 5}]
              width 10
              height 10
              background :dark_gray
            }

            @cubic_oval4 = oval {
              x          <= [@cubic, :x2_value, on_read: ->(val) {val - 5}]
              y          <= [@cubic, :y2_value, on_read: ->(val) {val - 5}]
              width 10
              height 10
              background :black
            }

            on_mouse_down do |mouse_event|
              @selected_shape = @cubic_canvas.shape_at_location(mouse_event.x, mouse_event.y)
              @selected_shape = nil unless @selected_shape.is_a?(Glimmer::SWT::Custom::Shape::Oval)
              @cubic_canvas.cursor = :hand if @selected_shape
            end

            on_drag_detected do |drag_detect_event|
              @drag_detected = true
              @drag_current_x = drag_detect_event.x
              @drag_current_y = drag_detect_event.y
            end

            on_mouse_move do |mouse_event|
              if @drag_detected && @selected_shape
                delta_x = mouse_event.x - @drag_current_x
                delta_y = mouse_event.y - @drag_current_y
                case @selected_shape
                when @cubic_oval1
                  @cubic.x1_value += delta_x
                  @cubic.y1_value += delta_y
                when @cubic_oval2
                  @cubic.cx1_value += delta_x
                  @cubic.cy1_value += delta_y
                when @cubic_oval3
                  @cubic.cx2_value += delta_x
                  @cubic.cy2_value += delta_y
                when @cubic_oval4
                  @cubic.x2_value += delta_x
                  @cubic.y2_value += delta_y
                end
                @drag_current_x = mouse_event.x
                @drag_current_y = mouse_event.y
              end
            end

            on_mouse_up do |mouse_event|
              @cubic_canvas.cursor = :arrow
              @drag_detected = false
              @selected_shape = nil
            end
          }
        }
      }
    }
  }
end

HelloCanvasDataBinding.launch
Enter fullscreen mode Exit fullscreen mode

Updated Hello, Canvas Data-Binding! Video Tutorial

YouTube:

Glimmer On!

Top comments (0)