Class: GlimR::Layout

Inherits:
Widget show all
Defined in:
lib/glimr/widgets/layout.rb

Overview

A Layout is a Widget that layouts its child widgets.

Layouts come in two breeds: the horizontal layout and the vertical layout. A horizontal layout (or HLayout) arranges its children in a row, while a vertical layout (a.k.a. VLayout) arranges them in a column.

A layout has two alignment attributes, the #align and the #valign. Align determines where to put the children on the horizontal axis, and valign does the same on the vertical axis.

Align value :left aligns the left border of the layouted widgets and pushes them to the left border of the layout. Using :right as align does the same, except for the right border. The :center align aligns the centerline of the widgets with the layout’s centerline. The default align is :left.

Valign takes three values as well: :top, :bottom, and :middle. The default is :top, and aligns the top border of the widgets with the top border of the layout. To align to the bottom border, use :bottom. The :middle valign aligns the vertical midpoint of the widgets with the layout’s vertical midpoint.

Item spacing controls the amount of space between the layouted widgets. The default item spacing is 2.

A Layout fits its children by default and doesn’t expand to maximum width or height.

Direct Known Subclasses

HLayout, VLayout

Constant Summary

Constants included from Layoutable

GlimR::Layoutable::DIMENSIONS

Instance Attribute Summary collapse

Attributes inherited from Widget

#focused, #hover

Attributes included from Layoutable

#align, #valign

Attributes inherited from Model

#geometry, #material, #shader, #texture, #transform

Attributes inherited from SceneObject

#children, #drawables, #mtime, #parent, #viewport

Attributes included from EventListener

#event_listeners, #listener_count

Instance Method Summary collapse

Methods inherited from Widget

#activate, #blur, #click, #focus, for, #initialize, #key_down, #key_up, #lock, #mouse_down, #mouse_move, #mouse_out, #mouse_over, #mouse_up, #unlock

Methods included from Layoutable

#attach, #constant_size?, #detach, #expand!, #expand?, #expand_height, #expand_to_max_height!, #expand_to_max_width!, #expand_width, #fit_to_children!, #full_depth, #full_height, #full_width, #initialize, #inner_depth, #inner_height, #inner_width, #inspect, #layoutable_children, #margin, #margin=, #max_height=, #max_width=, #min_height=, #min_width=, #padding, #padding=, #parent=, #size_changing, size_changing_accessor, #tell_children_of_size_change, #x=, #y=

Methods inherited from Model

#absolute_transform, #apply, #initialize, #inspect, #pop_state, #push_state

Methods inherited from SceneObject

#<<, #absolute_geometry, #absolute_material, #absolute_shader, #absolute_texture, #absolute_transform, #absolute_transform_for_drawing, #add_drawables, #apply, #attach, #clone, #detach, #detach_self, #initialize, #inspect, #pop_state, #push_state, #remove_drawables, #render, #replace_node, #root, #touch!, #visible

Methods included from Configurable

#initialize

Methods included from EventListener

#add_event_listener, #decrement_listener_count, #dispatch_event, #event_root, #increment_listener_count, #initialize, #method_missing, #multicast_event, #process_event, #remove_event_listener

Constructor Details

This class inherits a constructor from GlimR::Widget

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class GlimR::EventListener

Instance Attribute Details

#directionObject

Returns the value of attribute direction.



39
40
41
# File 'lib/glimr/widgets/layout.rb', line 39

def direction
  @direction
end

#item_spacingObject

Returns the value of attribute item_spacing.



39
40
41
# File 'lib/glimr/widgets/layout.rb', line 39

def item_spacing
  @item_spacing
end

Instance Method Details

#calculate_free_heightObject



185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/glimr/widgets/layout.rb', line 185

def calculate_free_height
  return inner_height if @direction == :horizontal
  objs = layoutable_children
  fit_height_objs, constant_height_objs = objs.partition{|o| o.expand_height}
  if fit_height_objs.empty?
    0.0
  else
    const_height = constant_height_objs.inject(0){|cw, o|
      cw + o.full_height
    } + (objs.size - 1) * @item_spacing
    [0.0, (inner_height - const_height) / fit_height_objs.size].max
  end
end

#calculate_free_widthObject



171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/glimr/widgets/layout.rb', line 171

def calculate_free_width
  return inner_width if @direction == :vertical
  objs = layoutable_children
  fit_width_objs, constant_width_objs = objs.partition{|o| o.expand_width }
  if fit_width_objs.empty?
    0.0
  else
    const_width = constant_width_objs.inject(0){|cw, o|
      cw + o.full_width
    } + (objs.size - 1) * @item_spacing
    [0.0, (inner_width - const_width) / fit_width_objs.size].max
  end
end

#children_changeObject



49
50
51
52
# File 'lib/glimr/widgets/layout.rb', line 49

def children_change
  @free_width = @free_height = nil
  layout
end

#default_configObject



41
42
43
44
45
46
47
# File 'lib/glimr/widgets/layout.rb', line 41

def default_config
  super.merge(
    :item_spacing => 2,
    :direction => :horizontal,
    :fit_children => true
  )
end

#fit_height!Object

If direction is horizontal, sets height equal to the largest child + padding. If direction is vertical, sets height to sum of children heights + padding + item spacing.



65
66
67
68
69
70
# File 'lib/glimr/widgets/layout.rb', line 65

def fit_height!
  return super if direction == :horizontal
  self.height = layoutable_children.inject(padding_top+padding_left-item_spacing){|s,c|
    s + c.full_height + item_spacing
  } unless layoutable_children.empty?
end

#fit_width!Object

If direction is vertical, sets width equal to the largest child + padding. If direction is horizontal, sets width to sum of children widths + padding + item spacing.



56
57
58
59
60
61
# File 'lib/glimr/widgets/layout.rb', line 56

def fit_width!
  return super if direction == :vertical
  self.width = layoutable_children.inject(padding_left+padding_right-item_spacing){|s,c|
    s + c.full_width + item_spacing
  } unless layoutable_children.empty?
end

#free_heightObject



167
168
169
# File 'lib/glimr/widgets/layout.rb', line 167

def free_height
  @free_height ||= calculate_free_height
end

#free_widthObject



163
164
165
# File 'lib/glimr/widgets/layout.rb', line 163

def free_width
  @free_width ||= calculate_free_width
end

#horiz_tile(objs) ⇒ Object

Horizontally tile objects inside self.



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/glimr/widgets/layout.rb', line 106

def horiz_tile(objs)
  objs_width = objs.inject(-@item_spacing){|s,o|
    s + o.full_width + @item_spacing
  }
  x = case @align
      when :left
        @padding_left
      when :right
        @padding_left + inner_width - objs_width
      when :center, :middle
        @padding_left + (inner_width - objs_width) / 2
      end
  ih = inner_height
  objs.each{|obj|
    obj.x = x + obj.margin_left
    obj.y = case @valign
            when :top
              @padding_top
            when :bottom
              @padding_top + ih - obj.full_height
            when :center, :middle
              @padding_top + (ih - obj.full_height) / 2
            end
    obj.z = 1
    x += obj.full_width + @item_spacing
  }
end

#layoutObject



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/glimr/widgets/layout.rb', line 72

def layout
  return if @layouting
  c = layoutable_children
  return if c.empty?
  @layouting = true
  size_changing do
    @free_width = @free_height = nil
    @id ||= 0
    @id += 1
    c.each{|ch|
      ch.width = free_width-ch.margin_left-ch.margin_right if ch.expand_width
      ch.height = free_height-ch.margin_top-ch.margin_bottom if ch.expand_height
    }
    fit_to_children! if fit_children?
    if @direction == :horizontal
      horiz_tile(c)
    else
      vert_tile(c)
    end
  end
  @layouting = false
end

#vert_tile(objs) ⇒ Object

Vertically tile objects inside self.



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/glimr/widgets/layout.rb', line 135

def vert_tile(objs)
  objs_height = objs.inject(-@item_spacing){|s,o|
    s + o.full_height + @item_spacing
  }
  y = case @align
      when :left
        @padding_top
      when :right
        @padding_top + inner_height - objs_height
      when :center, :middle
        @padding_top + (inner_height - objs_height) / 2
      end
  iw = inner_width
  objs.each{|obj|
    obj.y = y + obj.margin_top
    obj.x = case @align
            when :left
              @padding_left
            when :right
              @padding_left + iw - obj.full_width
            when :center, :middle
              @padding_left + (iw - obj.full_width) / 2
            end
    obj.z = 1
    y += obj.full_height + @item_spacing
  }
end