Class: Glimmer::Gtk::Shape

Inherits:
Object
  • Object
show all
Includes:
Transformable
Defined in:
lib/glimmer/gtk/shape.rb,
lib/glimmer/gtk/shape/arc.rb,
lib/glimmer/gtk/shape/path.rb,
lib/glimmer/gtk/shape/circle.rb,
lib/glimmer/gtk/shape/square.rb,
lib/glimmer/gtk/shape/polygon.rb,
lib/glimmer/gtk/shape/polyline.rb,
lib/glimmer/gtk/shape/triangle.rb,
lib/glimmer/gtk/shape/rectangle.rb,
lib/glimmer/gtk/shape/arc_negative.rb,
lib/glimmer/gtk/shape/rounded_rectangle.rb

Overview

Represents Gtk shape objects drawn on area widget, like rectangle, arc, and path

Defined Under Namespace

Classes: Arc, ArcNegative, Circle, Path, Polygon, Polyline, Rectangle, RoundedRectangle, Square, Triangle

Constant Summary collapse

SHAPE_FILL_PROPERTIES =
[:fill_rule]
SHAPE_STROKE_PROPERTIES =
[:dash, :line_cap, :line_join, :line_width, :miter_limit, :scaled_font]
SHAPE_GENERAL_PROPERTIES =
[:matrix, :operator, :tolerance]
SHAPE_FONT_PROPERTIES =
[:font_face, :font_matrix, :font_options, :font_size]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Transformable

#apply_transforms, #rotate, #scale, #translate

Constructor Details

#initialize(keyword, parent, args, &block) ⇒ Shape

TODO consider automatically setting attribute accessors by looking up set_xyz methods on cairo context



137
138
139
140
141
142
143
# File 'lib/glimmer/gtk/shape.rb', line 137

def initialize(keyword, parent, args, &block)
  @keyword = keyword
  @parent = parent
  @args = args
  @block = block
  post_add_content if @block.nil?
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_name, *args, &block) ⇒ Object



251
252
253
254
255
256
257
258
259
# File 'lib/glimmer/gtk/shape.rb', line 251

def method_missing(method_name, *args, &block)
  method_name = method_name.to_s
  if (method_name.start_with?('set_') && respond_to?("#{method_name.sub('set_', '')}=", true))
    args = [args] if args.size > 1
    send("#{method_name.sub('set_', '')}=", *args, &block)
  else
    super(method_name.to_sym, *args, &block)
  end
end

Instance Attribute Details

#argsObject (readonly)

Returns the value of attribute args.



132
133
134
# File 'lib/glimmer/gtk/shape.rb', line 132

def args
  @args
end

#blockObject (readonly)

Returns the value of attribute block.



132
133
134
# File 'lib/glimmer/gtk/shape.rb', line 132

def block
  @block
end

#clipObject

Returns the value of attribute clip.



133
134
135
# File 'lib/glimmer/gtk/shape.rb', line 133

def clip
  @clip
end

#fillObject

Returns the value of attribute fill.



133
134
135
# File 'lib/glimmer/gtk/shape.rb', line 133

def fill
  @fill
end

#keywordObject (readonly)

Returns the value of attribute keyword.



132
133
134
# File 'lib/glimmer/gtk/shape.rb', line 132

def keyword
  @keyword
end

#parentObject (readonly)

Returns the value of attribute parent.



132
133
134
# File 'lib/glimmer/gtk/shape.rb', line 132

def parent
  @parent
end

#strokeObject

Returns the value of attribute stroke.



133
134
135
# File 'lib/glimmer/gtk/shape.rb', line 133

def stroke
  @stroke
end

Class Method Details

.constant_symbol(keyword) ⇒ Object



79
80
81
# File 'lib/glimmer/gtk/shape.rb', line 79

def constant_symbol(keyword)
  keyword.camelcase(:upper).to_sym
end

.create(keyword, parent, args, &block) ⇒ Object



71
72
73
# File 'lib/glimmer/gtk/shape.rb', line 71

def create(keyword, parent, args, &block)
  shape_class(keyword).new(keyword, parent, args, &block)
end

.descendant_keyword_constant_mapObject



87
88
89
# File 'lib/glimmer/gtk/shape.rb', line 87

def descendant_keyword_constant_map
  @descendant_keyword_constant_map ||= map_descendant_keyword_constants_for(self)
end

.exist?(keyword) ⇒ Boolean

Returns:

  • (Boolean)


67
68
69
# File 'lib/glimmer/gtk/shape.rb', line 67

def exist?(keyword)
  shape_class(keyword)
end

.keyword(constant_symbol) ⇒ Object



83
84
85
# File 'lib/glimmer/gtk/shape.rb', line 83

def keyword(constant_symbol)
  constant_symbol.to_s.underscore
end

.map_descendant_keyword_constants_for(klass, accumulator: {}) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
# File 'lib/glimmer/gtk/shape.rb', line 96

def map_descendant_keyword_constants_for(klass, accumulator: {})
  klass.constants.map do |constant_symbol|
    [constant_symbol, klass.const_get(constant_symbol)]
  end.select do |constant_symbol, constant|
    constant.is_a?(Module) && !accumulator.values.include?(constant)
  end.each do |constant_symbol, constant|
    accumulator[keyword(constant_symbol)] = constant
    map_descendant_keyword_constants_for(constant, accumulator: accumulator)
  end
  accumulator
end

.one_based_color_rgb(rgb) ⇒ Object



108
109
110
111
# File 'lib/glimmer/gtk/shape.rb', line 108

def one_based_color_rgb(rgb)
  return rgb if rgb.is_a?(Cairo::Pattern) || rgb.first.is_a?(Cairo::ImageSurface)
  rgb.each_with_index.map {|single_color, i| i == 3 ? single_color : single_color / 255.0}
end

.reset_descendant_keyword_constant_mapObject



91
92
93
94
# File 'lib/glimmer/gtk/shape.rb', line 91

def reset_descendant_keyword_constant_map
  @descendant_keyword_constant_map = nil
  descendant_keyword_constant_map
end

.set_source_dynamically(cairo_context, source_args) ⇒ Object



113
114
115
116
117
118
119
120
121
122
# File 'lib/glimmer/gtk/shape.rb', line 113

def set_source_dynamically(cairo_context, source_args)
  source_args = one_based_color_rgb(source_args)
  if source_args.is_a?(Cairo::Pattern) || source_args.first.is_a?(Cairo::ImageSurface)
    cairo_context.set_source(*source_args)
  elsif source_args.size == 3
    cairo_context.set_source_rgb(*source_args)
  elsif source_args.size == 4
    cairo_context.set_source_rgba(*source_args)
  end
end

.shape_class(keyword) ⇒ Object



75
76
77
# File 'lib/glimmer/gtk/shape.rb', line 75

def shape_class(keyword)
  descendant_keyword_constant_map[keyword]
end

Instance Method Details

#apply_property(cairo_context, property) ⇒ Object



235
236
237
238
239
240
241
242
243
# File 'lib/glimmer/gtk/shape.rb', line 235

def apply_property(cairo_context, property)
  if send(property)
    if property == :font_face
      cairo_context.send("select_#{property}", *send(property))
    else
      cairo_context.send("set_#{property}", *send(property))
    end
  end
end

#content(&block) ⇒ Object



159
160
161
# File 'lib/glimmer/gtk/shape.rb', line 159

def content(&block)
  Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::Gtk::ShapeExpression.new, @keyword, &block)
end

#draw(drawing_area_widget, cairo_context) ⇒ Object

Subclasses must either implement draw_shape hook method or override this method directly



164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/glimmer/gtk/shape.rb', line 164

def draw(drawing_area_widget, cairo_context)
  if fill
    draw_font(drawing_area_widget, cairo_context)
    draw_shape(drawing_area_widget, cairo_context)
    draw_fill(drawing_area_widget, cairo_context)
  end
  
  if stroke
    draw_font(drawing_area_widget, cairo_context)
    draw_shape(drawing_area_widget, cairo_context)
    draw_stroke(drawing_area_widget, cairo_context)
  end
  
  if clip
    draw_font(drawing_area_widget, cairo_context)
    draw_shape(drawing_area_widget, cairo_context)
    draw_clip(drawing_area_widget, cairo_context)
  end
end

#draw_clip(drawing_area_widget, cairo_context) ⇒ Object



225
226
227
228
229
230
231
232
233
# File 'lib/glimmer/gtk/shape.rb', line 225

def draw_clip(drawing_area_widget, cairo_context)
  previous_matrix = cairo_context.matrix
  apply_transforms(cairo_context, target: :clip)
  SHAPE_GENERAL_PROPERTIES.each do |property|
    apply_property(cairo_context, property)
  end
  cairo_context.clip
  cairo_context.set_matrix(previous_matrix)
end

#draw_fill(drawing_area_widget, cairo_context) ⇒ Object



197
198
199
200
201
202
203
204
205
206
# File 'lib/glimmer/gtk/shape.rb', line 197

def draw_fill(drawing_area_widget, cairo_context)
  previous_matrix = cairo_context.matrix
  apply_transforms(cairo_context, target: :fill)
  self.class.set_source_dynamically(cairo_context, fill)
  (SHAPE_GENERAL_PROPERTIES + SHAPE_FILL_PROPERTIES).each do |property|
    apply_property(cairo_context, property)
  end
  cairo_context.fill
  cairo_context.set_matrix(previous_matrix)
end

#draw_font(drawing_area_widget, cairo_context) ⇒ Object



208
209
210
211
212
# File 'lib/glimmer/gtk/shape.rb', line 208

def draw_font(drawing_area_widget, cairo_context)
  SHAPE_FONT_PROPERTIES.each do |property|
    apply_property(cairo_context, property)
  end
end

#draw_shape(drawing_area_widget, cairo_context) ⇒ Object

Invokes cairo_context#underscored_shape_class_name method by default e.g. cairo_context.rectangle(0, 0, 200, 100) for Glimmer::Gtk::Shape::Rectangle (‘rectangle` keyword)

Subclasses can override



188
189
190
191
192
193
194
195
# File 'lib/glimmer/gtk/shape.rb', line 188

def draw_shape(drawing_area_widget, cairo_context)
  previous_matrix = cairo_context.matrix
  apply_transforms(cairo_context, target: :shape)
  class_symbol = self.class.name.split('::').last
  keyword = self.class.keyword(class_symbol)
  cairo_context.send(keyword, *args)
  cairo_context.set_matrix(previous_matrix)
end

#draw_stroke(drawing_area_widget, cairo_context) ⇒ Object



214
215
216
217
218
219
220
221
222
223
# File 'lib/glimmer/gtk/shape.rb', line 214

def draw_stroke(drawing_area_widget, cairo_context)
  previous_matrix = cairo_context.matrix
  apply_transforms(cairo_context, target: :stroke)
  self.class.set_source_dynamically(cairo_context, stroke)
  (SHAPE_GENERAL_PROPERTIES + SHAPE_STROKE_PROPERTIES).each do |property|
    apply_property(cairo_context, property)
  end
  cairo_context.stroke
  cairo_context.set_matrix(previous_matrix)
end

#post_add_contentObject

Subclasses may override to perform post add_content work (normally must call super)



146
147
148
# File 'lib/glimmer/gtk/shape.rb', line 146

def post_add_content
  @parent&.post_initialize_child(self)
end

#post_initialize_child(child) ⇒ Object

Subclasses may override to perform post initialization work on an added child (normally must also call super)



151
152
153
# File 'lib/glimmer/gtk/shape.rb', line 151

def post_initialize_child(child)
  # No Op for now. In the future, if we support relative-positioning nesting of shapes, this can be used/overridden
end

#respond_to?(method_name, include_private = false, &block) ⇒ Boolean

Returns:

  • (Boolean)


245
246
247
248
249
# File 'lib/glimmer/gtk/shape.rb', line 245

def respond_to?(method_name, include_private = false, &block)
  method_name = method_name.to_s
  (method_name.start_with?('set_') && super("#{method_name.sub('set_', '')}=", include_private)) ||
    super(method_name, include_private)
end

#window_proxyObject



155
156
157
# File 'lib/glimmer/gtk/shape.rb', line 155

def window_proxy
  @parent&.window_proxy
end