Source code for enable.stacked_layout
# (C) Copyright 2005-2022 Enthought, Inc., Austin, TX
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in LICENSE.txt and may be redistributed only under
# the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!
""" Routines for stacked layout of components in a container
"""
[docs]def stacked_preferred_size(container, components=None):
""" Returns the size (width,height) that is preferred for this component.
Overrides Component.
"""
if container.fixed_preferred_size is not None:
container._cached_preferred_size = container.fixed_preferred_size
return container.fixed_preferred_size
if container.resizable == "":
container._cached_preferred_size = container.outer_bounds[:]
return container.outer_bounds
if components is None:
components = container.components
ndx = container.stack_index
other_ndx = 1 - ndx
no_visible_components = True
total_size = 0
max_other_size = 0
for component in components:
if not container._should_layout(component):
continue
no_visible_components = False
pref_size = component.get_preferred_size()
total_size += pref_size[ndx] + container.spacing
if pref_size[other_ndx] > max_other_size:
max_other_size = pref_size[other_ndx]
if total_size >= container.spacing:
total_size -= container.spacing
if (container.stack_dimension not in container.resizable
and container.stack_dimension not in container.fit_components):
total_size = container.bounds[ndx]
elif no_visible_components or (total_size == 0):
total_size = container.default_size[ndx]
if (container.other_dimension not in container.resizable
and container.other_dimension not in container.fit_components):
max_other_size = container.bounds[other_ndx]
elif no_visible_components or (max_other_size == 0):
max_other_size = container.default_size[other_ndx]
if ndx == 0:
container._cached_preferred_size = (
total_size + container.hpadding,
max_other_size + container.vpadding,
)
else:
container._cached_preferred_size = (
max_other_size + container.hpadding,
total_size + container.vpadding,
)
return container._cached_preferred_size
[docs]def stack_layout(container, components, align):
""" Helper method that does the actual work of layout.
"""
size = list(container.bounds)
if container.fit_components != "":
container.get_preferred_size()
if "h" in container.fit_components:
size[0] = container._cached_preferred_size[0] - container.hpadding
if "v" in container.fit_components:
size[1] = container._cached_preferred_size[1] - container.vpadding
ndx = container.stack_index
other_ndx = 1 - ndx
other_dim = container.other_dimension
# Assign sizes of non-resizable components, and compute the total size
# used by them (along the stack dimension).
total_fixed_size = 0
resizable_components = []
size_prefs = {}
total_resizable_size = 0
for component in components:
if not container._should_layout(component):
continue
if container.stack_dimension not in component.resizable:
total_fixed_size += component.outer_bounds[ndx]
else:
preferred_size = component.get_preferred_size()
size_prefs[component] = preferred_size
total_resizable_size += preferred_size[ndx]
resizable_components.append(component)
new_bounds_dict = {}
# Assign sizes of all the resizable components along the stack dimension
if resizable_components:
space = container.spacing * (len(container.components) - 1)
avail_size = size[ndx] - total_fixed_size - space
if total_resizable_size > 0:
scale = avail_size / float(total_resizable_size)
for component in resizable_components:
tmp = list(component.outer_bounds)
tmp[ndx] = int(size_prefs[component][ndx] * scale)
new_bounds_dict[component] = tmp
else:
each_size = int(avail_size / len(resizable_components))
for component in resizable_components:
tmp = list(component.outer_bounds)
tmp[ndx] = each_size
new_bounds_dict[component] = tmp
# Loop over all the components, assigning position and computing the
# size in the other dimension and its position.
cur_pos = 0
for component in components:
if not container._should_layout(component):
continue
position = list(component.outer_position)
position[ndx] = cur_pos
bounds = new_bounds_dict.get(component, list(component.outer_bounds))
cur_pos += bounds[ndx] + container.spacing
if (bounds[other_ndx] > size[other_ndx]
or other_dim in component.resizable):
# If the component is resizable in the other dimension or it
# exceeds the container bounds, set it to the maximum size of the
# container
position[other_ndx] = 0
bounds[other_ndx] = size[other_ndx]
else:
position[other_ndx] = 0
if align == "min":
pass
elif align == "max":
position[other_ndx] = size[other_ndx] - bounds[other_ndx]
elif align == "center":
position[other_ndx] = (
size[other_ndx] - bounds[other_ndx]
) / 2.0
component.outer_position = position
component.outer_bounds = bounds
component.do_layout()