Class: CTioga::Layout

Inherits:
Object
  • Object
show all
Includes:
Log
Defined in:
lib/CTioga/layout.rb

Overview

Handles the gory details of placement of objects. It can be called to provide any of the specification for a subplot/subfigure, or the hash necessary to be fed to show_plot_with_legend.

Every layout object has a root object (object), the base one, the one which limits its capabilities. No layout object should touch anything that is not a descendant of the root object – or the root object itself.

In addition to that, the layout can handle many children of this root object that request it.

Direct Known Subclasses

SimpleLayout

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Log

#identify, #init_logger, #logger, #logger_options, #spawn

Constructor Details

#initialize(ro, ch = [], children = []) ⇒ Layout

Performs basic initialization. All descendants from this class should have at least three arguments, and at most three mandatory ones, always the same. Else, the convert_layout function won’t work, and that means trouble.



124
125
126
127
128
129
130
131
132
# File 'lib/CTioga/layout.rb', line 124

def initialize(ro, ch = [], children = [] )
  @object = ro
  @object.layout = self
  @child_layouts = []
  for c in children
    add_child(c)
  end
  @parent = nil
end

Instance Attribute Details

#child_layoutsObject

The layouts that would wish to report extensions information to this one.



114
115
116
# File 'lib/CTioga/layout.rb', line 114

def child_layouts
  @child_layouts
end

#objectObject

The object the layout is handling. Should never be null.



110
111
112
# File 'lib/CTioga/layout.rb', line 110

def object
  @object
end

#parentObject

The parent layout. Can be nil. Most of the layouts won’t reall take something from this.



118
119
120
# File 'lib/CTioga/layout.rb', line 118

def parent
  @parent
end

Instance Method Details

#add_child(child) ⇒ Object

Ask this layout to manage a child. No check is done to actually ensure that the child really is a child.



141
142
143
144
# File 'lib/CTioga/layout.rb', line 141

def add_child(child)
  child.parent = self
  @child_layouts << child
end

#compute_padding(object) ⇒ Object

Returns the padding for the given object, taking into account the position of legends:



253
254
255
256
257
258
259
260
261
262
263
# File 'lib/CTioga/layout.rb', line 253

def compute_padding(object)
  prefs = @object.layout_preferences
  padding = @object.layout_preferences.padding.dup

  # If the object has a legend 
  if @object.display_legend? && Utils::side?(prefs.legend_position)
    padding[Utils::side(prefs.legend_position)] = 
      prefs.legend_glue.dup
  end
  return padding
end

#convert_layout(cls) ⇒ Object

Converts self into another layout, whose class is cls.



135
136
137
# File 'lib/CTioga/layout.rb', line 135

def convert_layout(cls)
  return cls.new(object, @child_layouts)
end

#extension(t) ⇒ Object

Returns the extension of the layout



174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/CTioga/layout.rb', line 174

def extension(t)
  extensions = [0,0,0,0]
  # TODO: maybe this code should move within the PlotStyle object
  for a in [:title, :xlabel, :ylabel]
    update_extension_with_object(extensions, 
                                 @object.plot_style.send(a),
                                 t, @object.rescale || 1)
  end
  update_extension_with_object(extensions, @object.plot_style.edges,t)
  debug "Layout #{"%x" % self.object_id} extensions #{extensions.inspect}"
  return extensions
end

#legend_extension(t) ⇒ Object

Computes the extension for the legend, according to the position. Does not check if the object actually needs to display any legend whatsoever.



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/CTioga/layout.rb', line 190

def legend_extension(t)
  frame = @object.outer_frame(t)
  case @object.layout_preferences.legend_position
  when :left
    return [@object.layout_preferences.
            legend_size.to_absolute(frame, :horizontal),0,0,0]
  when :right
    return [0,@object.layout_preferences.
            legend_size.to_absolute(frame, :horizontal),0,0]
  when :top
    return [0,0,@object.layout_preferences.
            legend_size.to_absolute(frame, :vertical),0]
  when :bottom
    return [0,0,0,
            @object.layout_preferences.
            legend_size.to_absolute(frame, :vertical)]
  when :inside
    return [0,0,0,0]        # Inside doesn't count !
  else
    warn "Invalid legend position specification"
    return [0,0,0,0]        # Does not count.
  end
end

#legend_only_specs(t, padding) ⇒ Object

Converts the legend extension to a full legend specification.



219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# File 'lib/CTioga/layout.rb', line 219

def legend_only_specs(t, padding)
  frame = @object.outer_frame(t)
  case @object.layout_preferences.legend_position
  when :inside
    # Use the legend_spec without any other modification.
    return @object.layout_preferences.legend_spec
  else
    ext = legend_extension(t)
    mar = Dimension.absolute_to_relative(ext, frame)
  end

  target = [0,0,0,0]
  4.times do |i|
    if mar[i] > 0
      target[(i/2) * 2 + ((i+1) % 2)] = 1 - mar[i]
    end
  end

  # Now, the legend spec is nearly ready; we just need to
  # modify it so that it matches the sides of the plot.
  case @object.layout_preferences.legend_position
  when :left, :right
    target[2] = padding[2]
    target[3] = padding[3]
  when :top, :bottom
    target[0] = padding[0]
    target[1] = padding[1]
  end

  return target.to_frame("legend_%s_margin")
end

#legend_specs(object, t = nil) ⇒ Object

Returns the specs to be fed to show_plot_with_legend for the given object.

Defaults to full plot.



150
151
152
# File 'lib/CTioga/layout.rb', line 150

def legend_specs(object, t = nil)
  return [0,0,0,0].to_frame("plot_%s_margin")
end

#update_extension_with_object(extensions, object, t, scale = 1) ⇒ Object

A utility function that adds an extension as reported by Axes#extension (or any other, for what matters) to an already existing array of extensions. It will replace the current element unless it is smaller.



162
163
164
165
# File 'lib/CTioga/layout.rb', line 162

def update_extension_with_object(extensions, object, t, scale = 1)
  new_ext = object.extension(t,scale)
  return update_extensions(extensions, new_ext)
end

#update_extensions(extensions, new_ext) ⇒ Object

Simply updates the given extensions with the new ones, making sure that nall the objects can be crammed inside.



169
170
171
# File 'lib/CTioga/layout.rb', line 169

def update_extensions(extensions, new_ext)
  return Dimension.update_extensions(extensions, new_ext)
end