Glimmer DSL for LibUI (Ruby Desktop Development Cross-Platform Native GUI Library) versions 0.10.1 & 0.10.0 ship with support for building and scaffolding Area Canvas Graphics Custom Shapes (with optional Gemification). Custom shapes represent higher-order graphical concepts, like `cube`, `cylinder`, and `uml_class`, that could be formed out of more rudimentary shapes like `rectangle`, `circle`, `bezier`, and `text`, to aggregate and simplify interaction with them as coarse-grained components in a desktop application. Custom Shapes improve productivity significantly through code reuse in graphical desktop applications that rely on Area Canvas Graphics, like UML Diagramming tools, Traffic Control Signalling apps, and games. When defining Custom Shapes, the Glimmer GUI DSL automatically grows with new keywords that represent new shapes like `cube`, `cylinder`, and `uml_class`. To do so, simply define classes matching the names of the shapes in standard Ruby class camelcase (e.g. `Cube`, `Cylinder`, and `UmlClass`) and mix in the `Glimmer::LibUI::CustomShape` module, and Glimmer will automatically augment its DSL with matching underscored keywords by convention (`cube`, `cylinder`, and `uml_class`). Custom Shapes enable dreaming up any aggregate visual concepts and implementing them as components in the same way we think about them.
A Custom Shape can be scaffolded inside a Glimmer DSL for LibUI application with the `glimmer "scaffold:customshape[name,namespace]"` command.
Alternatively, a Custom Shape Gem can be scaffolded as its own separate project with the `glimmer "scaffold:gem:customshape[name,namespace]"` in order to facilitate sharing a Custom Shape across multiple desktop applications.
A new example was included in Glimmer DSL for LibUI called Basic Custom Shape:
# Source: https://github.com/AndyObtiva/glimmer-dsl-libui/blob/master/docs/examples/GLIMMER-DSL-LIBUI-BASIC-EXAMPLES.md#basic-custom-shape | |
require 'glimmer-dsl-libui' | |
# This is the class-based custom shape version of basic_composite_shape | |
# class-based custom shape using Glimmer::LibUI::CustomShape mixin, which automatically | |
# augments the Glimmer GUI DSL with the underscored version of the class name: `cube` | |
# while accepting hash options matching the options declared on the class. | |
# (e.g. `cube(location_x: 50, location_y: 100)` ) | |
class Cube | |
include Glimmer::LibUI::CustomShape | |
DEFAULT_SIZE = 28 | |
option :location_x, default: 0 | |
option :location_y, default: 0 | |
option :rectangle_width, default: nil | |
option :rectangle_height, default: nil | |
option :cube_height, default: 75 | |
option :background_color, default: :brown | |
option :foreground_color | |
option :line_thickness, default: 1 | |
# The before_body block executes before building the body | |
before_body do | |
self.rectangle_width ||= rectangle_height || cube_height || DEFAULT_SIZE | |
self.rectangle_height ||= rectangle_width || cube_height || DEFAULT_SIZE | |
self.cube_height ||= rectangle_width || rectangle_height || DEFAULT_SIZE | |
if foreground_color | |
self.foreground_color = Glimmer::LibUI.interpret_color(foreground_color) | |
self.foreground_color[:thickness] ||= line_thickness | |
else | |
self.foreground_color = [0, 0, 0, thickness: line_thickness] | |
end | |
end | |
# Optionally, after_body could be defined to perform operations after building the body | |
# like setting up observers. | |
# | |
# after_body do | |
# end | |
body { | |
# the shape keyword (alias for composite_shape) enables building a composite shape that is treated as one shape | |
# like a cube containing polygons, a polyline, a rectangle, and a line | |
# with the fill and stroke colors getting inherited by all children that do not specify them | |
shape(location_x, location_y) { | |
fill background_color | |
stroke foreground_color | |
bottom = polygon(0, cube_height + rectangle_height / 2.0, | |
rectangle_width / 2.0, cube_height, | |
rectangle_width, cube_height + rectangle_height / 2.0, | |
rectangle_width / 2.0, cube_height + rectangle_height) { | |
# inherits fill property from parent shape if not set | |
# inherits stroke property from parent shape if not set | |
} | |
body = rectangle(0, rectangle_height / 2.0, rectangle_width, cube_height) { | |
# inherits fill property from parent shape if not set | |
# stroke is overridden to ensure a different value from parent | |
stroke thickness: 0 | |
} | |
polyline(0, rectangle_height / 2.0 + cube_height, | |
0, rectangle_height / 2.0, | |
rectangle_width, rectangle_height / 2.0, | |
rectangle_width, rectangle_height / 2.0 + cube_height) { | |
# inherits stroke property from parent shape if not set | |
} | |
top = polygon(0, rectangle_height / 2.0, | |
rectangle_width / 2.0, 0, | |
rectangle_width, rectangle_height / 2.0, | |
rectangle_width / 2.0, rectangle_height) { | |
# inherits fill property from parent shape if not set | |
# inherits stroke property from parent shape if not set | |
} | |
line(rectangle_width / 2.0, cube_height + rectangle_height, | |
rectangle_width / 2.0, rectangle_height) { | |
# inherits stroke property from parent shape if not set | |
} | |
} | |
} | |
end | |
class BasicCustomShape | |
include Glimmer::LibUI::Application | |
body { | |
window { | |
title 'Basic Custom Shape' | |
content_size 200, 225 | |
@area = area { | |
rectangle(0, 0, 200, 225) { | |
fill :white | |
} | |
7.times do |n| | |
x_location = (rand*125).to_i%200 + (rand*15).to_i | |
y_location = (rand*125).to_i%200 + (rand*15).to_i | |
shape_color = [rand*125 + 130, rand*125 + 130, rand*125 + 130] | |
shape_size = 20+n | |
cube( | |
location_x: x_location, | |
location_y: y_location, | |
rectangle_width: shape_size*2, | |
rectangle_height: shape_size, | |
cube_height: shape_size*2, | |
background_color: shape_color, | |
line_thickness: 2 | |
) { |the_shape| | |
on_mouse_up do |area_mouse_event| | |
# Change color on mouse up without dragging | |
if @drag_shape.nil? | |
background_color = [rand(255), rand(255), rand(255)] | |
the_shape.fill = background_color | |
end | |
end | |
on_mouse_drag_start do |area_mouse_event| | |
@drag_shape = the_shape | |
@drag_x = area_mouse_event[:x] | |
@drag_y = area_mouse_event[:y] | |
end | |
on_mouse_drag do |area_mouse_event| | |
if @drag_shape && @drag_x && @drag_y | |
drag_distance_width = area_mouse_event[:x] - @drag_x | |
drag_distance_height = area_mouse_event[:y] - @drag_y | |
@drag_shape.x += drag_distance_width | |
@drag_shape.y += drag_distance_height | |
@drag_x = area_mouse_event[:x] | |
@drag_y = area_mouse_event[:y] | |
end | |
end | |
on_mouse_drop do |area_mouse_event| | |
@drag_shape = nil | |
@drag_x = nil | |
@drag_y = nil | |
end | |
} | |
end | |
# this general area on_mouse_drag listener is needed to ensure that dragging a shape | |
# outside of its boundaries would still move the dragged shape | |
on_mouse_drag do |area_mouse_event| | |
if @drag_shape && @drag_x && @drag_y | |
drag_distance_width = area_mouse_event[:x] - @drag_x | |
drag_distance_height = area_mouse_event[:y] - @drag_y | |
@drag_shape.x += drag_distance_width | |
@drag_shape.y += drag_distance_height | |
@drag_x = area_mouse_event[:x] | |
@drag_y = area_mouse_event[:y] | |
end | |
end | |
on_mouse_drop do |area_mouse_event| | |
@drag_shape = nil | |
@drag_x = nil | |
@drag_y = nil | |
end | |
} | |
} | |
} | |
end | |
BasicCustomShape.launch | |
Glimmer on!!!
No comments:
Post a Comment