diff --git a/.github/workflows/test-with-edm.yml b/.github/workflows/test-with-edm.yml index f9ff7fb0f..5b931b3f9 100644 --- a/.github/workflows/test-with-edm.yml +++ b/.github/workflows/test-with-edm.yml @@ -32,6 +32,12 @@ jobs: sudo apt-get install libxcb-render-util0 sudo apt-get install libxcb-xinerama0 if: matrix.toolkit != 'null' + # NOTE : Temporarily needed for building enable from source + # Should be removed when enable 5.2 is released + - name: Install GL dependencies necessary to build enable + run: | + sudo apt-get update + sudo apt-get install libglu1-mesa-dev - name: Cache EDM packages uses: actions/cache@v2 with: diff --git a/chaco/plot_containers.py b/chaco/plot_containers.py index 179467db1..6dcbe6d4c 100644 --- a/chaco/plot_containers.py +++ b/chaco/plot_containers.py @@ -33,15 +33,14 @@ Instance, List, Property, + Str, String, Trait, Tuple, Int, ) -from enable.simple_layout import ( - simple_container_get_preferred_size, - simple_container_do_layout, -) +from enable.api import OverlayContainer +from enable.stacked_container import HStackedContainer, VStackedContainer try: from enable.api import ConstraintsContainer @@ -88,7 +87,7 @@ class ConstraintsPlotContainer(ConstraintsContainer): __all__.append("ConstraintsPlotContainer") -class OverlayPlotContainer(BasePlotContainer): +class OverlayPlotContainer(OverlayContainer): """ A plot container that stretches all its components to fit within its space. All of its components must therefore be resizable. @@ -102,189 +101,30 @@ class OverlayPlotContainer(BasePlotContainer): # Cache (width, height) of the container's preferred size. _cached_preferred_size = Tuple - def get_preferred_size(self, components=None): - """Returns the size (width,height) that is preferred for this component. - - Overrides PlotComponent - """ - return simple_container_get_preferred_size(self, components=components) + #: Redefine the container layers to name the main layer as "plot" instead + #: of the Enable default of "mainlayer" + container_under_layers = Tuple("background", "image", "underlay", "plot") - def _do_layout(self): - """Actually performs a layout (called by do_layout()).""" - simple_container_do_layout(self) + draw_layer = Str("plot") -class StackedPlotContainer(BasePlotContainer): +class HPlotContainer(HStackedContainer): """ - Base class for 1-D stacked plot containers, both horizontal and vertical. + A plot container that stacks all of its components horizontally. Resizable + components share the free space evenly. All components are stacked from + according to **stack_order* in the same order that they appear in the + **components** list. """ - draw_order = Instance(list, args=(DEFAULT_DRAWING_ORDER,)) - - # The dimension along which to stack components that are added to - # this container. - stack_dimension = Enum("h", "v", transient=True) + #: Redefine the container layers to name the main layer as "plot" instead + #: of the Enable default of "mainlayer" + container_under_layers = Tuple("background", "image", "underlay", "plot") - # The "other" dimension, i.e., the dual of the stack dimension. - other_dimension = Enum("v", "h", transient=True) - - # The index into obj.position and obj.bounds that corresponds to - # **stack_dimension**. This is a class-level and not an instance-level - # attribute. It must be 0 or 1. - stack_index = 0 - - def get_preferred_size(self, components=None): - """Returns the size (width,height) that is preferred for this component. - - Overrides PlotComponent. - """ - if self.fixed_preferred_size is not None: - self._cached_preferred_size = self.fixed_preferred_size - return self.fixed_preferred_size - - if self.resizable == "": - self._cached_preferred_size = self.outer_bounds[:] - return self.outer_bounds - - if components is None: - components = self.components - - ndx = self.stack_index - other_ndx = 1 - ndx - - no_visible_components = True - total_size = 0 - max_other_size = 0 - for component in components: - if not self._should_layout(component): - continue - - no_visible_components = False - - pref_size = component.get_preferred_size() - total_size += pref_size[ndx] + self.spacing - if pref_size[other_ndx] > max_other_size: - max_other_size = pref_size[other_ndx] - - if total_size >= self.spacing: - total_size -= self.spacing - - if (self.stack_dimension not in self.resizable) and ( - self.stack_dimension not in self.fit_components - ): - total_size = self.bounds[ndx] - elif no_visible_components or (total_size == 0): - total_size = self.default_size[ndx] - - if (self.other_dimension not in self.resizable) and ( - self.other_dimension not in self.fit_components - ): - max_other_size = self.bounds[other_ndx] - elif no_visible_components or (max_other_size == 0): - max_other_size = self.default_size[other_ndx] - - if ndx == 0: - self._cached_preferred_size = ( - total_size + self.hpadding, - max_other_size + self.vpadding, - ) - else: - self._cached_preferred_size = ( - max_other_size + self.hpadding, - total_size + self.vpadding, - ) - - return self._cached_preferred_size - - def _do_stack_layout(self, components, align): - """Helper method that does the actual work of layout.""" - - size = list(self.bounds) - if self.fit_components != "": - self.get_preferred_size() - if "h" in self.fit_components: - size[0] = self._cached_preferred_size[0] - self.hpadding - if "v" in self.fit_components: - size[1] = self._cached_preferred_size[1] - self.vpadding - - ndx = self.stack_index - other_ndx = 1 - ndx - other_dim = self.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 self._should_layout(component): - continue - if self.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 = self.spacing * (len(self.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 self._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] + self.spacing + draw_layer = Str("plot") - 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 + draw_order = Instance(list, args=(DEFAULT_DRAWING_ORDER,)) - 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() + _cached_preferred_size = Tuple(transient=True) ### Persistence ########################################################### @@ -296,83 +136,29 @@ def __getstate__(self): return state -class HPlotContainer(StackedPlotContainer): - """ - A plot container that stacks all of its components horizontally. Resizable - components share the free space evenly. All components are stacked from - according to **stack_order* in the same order that they appear in the - **components** list. - """ - - draw_order = Instance(list, args=(DEFAULT_DRAWING_ORDER,)) - - #: The order in which components in the plot container are laid out. - stack_order = Enum("left_to_right", "right_to_left") - - #: The amount of space to put between components. - spacing = Float(0.0) - - #: The vertical alignment of objects that don't span the full height. - valign = Enum("bottom", "top", "center") - - _cached_preferred_size = Tuple(transient=True) - - def _do_layout(self): - """Actually performs a layout (called by do_layout()).""" - if self.stack_order == "left_to_right": - components = self.components - else: - components = self.components[::-1] - - if self.valign == "bottom": - align = "min" - elif self.valign == "center": - align = "center" - else: - align = "max" - - return self._do_stack_layout(components, align) - - -class VPlotContainer(StackedPlotContainer): +class VPlotContainer(VStackedContainer): """ A plot container that stacks plot components vertically. """ - draw_order = Instance(list, args=(DEFAULT_DRAWING_ORDER,)) + #: Redefine the container layers to name the main layer as "plot" instead + #: of the Enable default of "mainlayer" + container_under_layers = Tuple("background", "image", "underlay", "plot") - #: Overrides StackedPlotContainer. - stack_dimension = "v" - #: Overrides StackedPlotContainer. - other_dimension = "h" - #: Overrides StackedPlotContainer. - stack_index = 1 + draw_layer = Str("plot") - # VPlotContainer attributes - - #: The horizontal alignment of objects that don't span the full width. - halign = Enum("left", "right", "center") - - #: The order in which components in the plot container are laid out. - stack_order = Enum("bottom_to_top", "top_to_bottom") + draw_order = Instance(list, args=(DEFAULT_DRAWING_ORDER,)) - #: The amount of space to put between components. - spacing = Float(0.0) + _cached_preferred_size = Tuple(transient=True) - def _do_layout(self): - """Actually performs a layout (called by do_layout()).""" - if self.stack_order == "bottom_to_top": - components = self.components - else: - components = self.components[::-1] - if self.halign == "left": - align = "min" - elif self.halign == "center": - align = "center" - else: - align = "max" + ### Persistence ########################################################### - return self._do_stack_layout(components, align) + # PICKLE FIXME: blocked with _pickles, but not sure that was correct. + def __getstate__(self): + state = super().__getstate__() + if "stack_index" in state: + del state["stack_index"] + return state class GridPlotContainer(BasePlotContainer): diff --git a/ci/edmtool.py b/ci/edmtool.py index f8504f341..40163bc01 100644 --- a/ci/edmtool.py +++ b/ci/edmtool.py @@ -218,6 +218,25 @@ def install(runtime, toolkit, environment, editable, source): click.echo("Creating environment '{environment}'".format(**parameters)) execute(commands, parameters) + # NOTE : temporary code to install enable from source instead of relying on + # enable 5.1.1. This should be removed immediately after enable 5.2.0 is + # released. + command = "edm plumbing remove-package --environment {environment} --force enable" # noqa + execute([command], parameters) + source_pkgs = [ + "git+http://github.com/enthought/enable.git@maint/5.2#egg=enable" + ] + # Without the --no-dependencies flag such that new dependencies on + # master are brought in. + commands = [ + "python -m pip install --force-reinstall {pkg} ".format(pkg=pkg) + for pkg in source_pkgs + ] + commands = [ + "edm run -e {environment} -- " + command for command in commands + ] + execute(commands, parameters) + if source: # Remove EDM ETS packages and install them from source cmd_fmt = (