Ticket #4025: 0003-Improve-circle-and-spiral-layout-favourite-view-to-i.patch

File 0003-Improve-circle-and-spiral-layout-favourite-view-to-i.patch, 6.8 KB (added by manuq, 9 years ago)

Follow up patch.

  • src/jarabe/desktop/favoriteslayout.py

    From a17ad3cd7d415a35d52dd4365140ff5e80d513c4 Mon Sep 17 00:00:00 2001
    From: Gary Martin <gary@garycmartin.com>
    Date: Thu, 11 Oct 2012 04:17:04 +0100
    Subject: [PATCH shell 3/3] Improve circle and spiral layout favourite view to
     improve touch interaction - SL #4025
    Mail-Followup-To: <sugar-devel@lists.sugarlabs.org>
    
    The original controls provided for RingLayout did not allow clean
    enough control of the circle and spiral icon layout. The global arrays
    of hard coded icon spacing at discrete icon size steps has now been
    replaced with a continuous function that will much more smoothly
    layout from 0 up to a large number of activities (a wider range of
    testing and comparison with previous behaviour was done with up to 55
    activities). The layout now make better use of the available canvas
    space using larger icons, smaller steps between icon sizes, and larger
    circle/spiral arrangements to try and maximise both icon hit target
    size and provide enough space between icons to minimise target miss
    press errors.
    
    This patch switches from fixed intermadiate sizes (the removed
    _INTERMEDIATE_* constants) to dynamic intermadiate sizes.
    ---
     src/jarabe/desktop/favoriteslayout.py | 80 +++++++++++++++++++----------------
     1 file changed, 43 insertions(+), 37 deletions(-)
    
    diff --git a/src/jarabe/desktop/favoriteslayout.py b/src/jarabe/desktop/favoriteslayout.py
    index 3c9be8b..5f3b560 100644
    a b _logger = logging.getLogger('FavoritesLayout') 
    3333
    3434_CELL_SIZE = 4
    3535_BASE_SCALE = 1000
    36 _INTERMEDIATE_B = (style.STANDARD_ICON_SIZE + style.SMALL_ICON_SIZE) / 2
    37 _INTERMEDIATE_A = (style.STANDARD_ICON_SIZE + _INTERMEDIATE_B) / 2
    38 _INTERMEDIATE_C = (_INTERMEDIATE_B + style.SMALL_ICON_SIZE) / 2
    39 _ICON_SIZES = [style.MEDIUM_ICON_SIZE, style.STANDARD_ICON_SIZE,
    40                _INTERMEDIATE_A, _INTERMEDIATE_B, _INTERMEDIATE_C,
    41                style.SMALL_ICON_SIZE]
    4236
    4337
    4438class Layout(object):
    class RandomLayout(SpreadLayout): 
    279273        self.fixed_positions[child] = (x, y)
    280274
    281275
    282 _MINIMUM_RADIUS = style.XLARGE_ICON_SIZE / 2 + style.DEFAULT_SPACING + \
    283         style.STANDARD_ICON_SIZE * 2
     276_MINIMUM_RADIUS = style.XLARGE_ICON_SIZE / 2 + style.DEFAULT_SPACING
    284277_MAXIMUM_RADIUS = (Gdk.Screen.height() - style.GRID_CELL_SIZE) / 2 - \
    285         style.STANDARD_ICON_SIZE - style.DEFAULT_SPACING
    286 _ICON_SPACING_FACTORS = [1.5, 1.4, 1.3, 1.2, 1.1, 1.0]
    287 _SPIRAL_SPACING_FACTORS = [1.5, 1.5, 1.5, 1.4, 1.3, 1.2]
    288 _MIMIMUM_RADIUS_ENCROACHMENT = 0.75
     278        style.DEFAULT_SPACING
     279_RING_SPACING_FACTOR = 0.95
     280_SPIRAL_SPACING_FACTOR = 0.75
     281_RADIUS_GROWTH_FACTOR = 1.25
     282_MIMIMUM_RADIUS_PADDING_FACTOR = 0.85
     283_MAXIMUM_RADIUS_PADDING_FACTOR = 1.25
    289284_INITIAL_ANGLE = math.pi
    290285
    291286
    class RingLayout(ViewLayout): 
    308303    def _calculate_radius_and_icon_size(self, children_count):
    309304        """ Adjust the ring or spiral radius and icon size as needed. """
    310305        self._spiral_mode = False
    311         distance = style.MEDIUM_ICON_SIZE + style.DEFAULT_SPACING * \
    312             _ICON_SPACING_FACTORS[_ICON_SIZES.index(style.MEDIUM_ICON_SIZE)]
    313         radius = max(children_count * distance / (2 * math.pi),
    314                      _MINIMUM_RADIUS)
    315         if radius < _MAXIMUM_RADIUS:
    316             return radius, style.MEDIUM_ICON_SIZE
    317 
    318         distance = style.STANDARD_ICON_SIZE + style.DEFAULT_SPACING * \
    319             _ICON_SPACING_FACTORS[_ICON_SIZES.index(style.STANDARD_ICON_SIZE)]
    320         radius = max(children_count * distance / (2 * math.pi),
    321                      _MINIMUM_RADIUS)
    322         if radius < _MAXIMUM_RADIUS:
    323             return radius, style.STANDARD_ICON_SIZE
    324306
    325         self._spiral_mode = True
    326         icon_size = style.STANDARD_ICON_SIZE
     307        icon_size = style.MEDIUM_ICON_SIZE
    327308        angle_, radius = self._calculate_angle_and_radius(children_count,
    328309                                                          icon_size)
    329         while radius > _MAXIMUM_RADIUS:
    330             i = _ICON_SIZES.index(icon_size)
    331             if i < len(_ICON_SIZES) - 1:
    332                 icon_size = _ICON_SIZES[i + 1]
     310        if radius <= self._calculate_maximum_radius(icon_size):
     311            return radius, icon_size
     312        while radius > self._calculate_maximum_radius(icon_size):
     313            icon_size -= 1
     314            if icon_size <= style.STANDARD_ICON_SIZE:
     315                break
     316            else:
    333317                angle_, radius = self._calculate_angle_and_radius(
    334318                    children_count, icon_size)
    335             else:
     319        if radius <= self._calculate_maximum_radius(icon_size):
     320            return radius, icon_size
     321
     322        self._spiral_mode = True
     323        icon_size = style.MEDIUM_ICON_SIZE
     324        while radius > self._calculate_maximum_radius(icon_size):
     325            if icon_size < style.SMALL_ICON_SIZE:
    336326                break
     327            else:
     328                angle_, radius = self._calculate_angle_and_radius(
     329                    children_count, icon_size)
     330            icon_size -= 1
    337331        return radius, icon_size
    338332
    339333    def _calculate_position(self, radius, icon_size, icon_index,
    class RingLayout(ViewLayout): 
    362356        y = y + (height - icon_size - (style.GRID_CELL_SIZE / 2)) / 2
    363357        return x, y
    364358
     359    def _calculate_maximum_radius(self, icon_size):
     360        """ Return the maximum radius including encroachment. """
     361        return _MAXIMUM_RADIUS - (icon_size * _MAXIMUM_RADIUS_PADDING_FACTOR)
     362
    365363    def _calculate_angle_and_radius(self, icon_count, icon_size):
    366364        """ Based on icon_count and icon_size, calculate radius and angle. """
    367         spiral_spacing = _SPIRAL_SPACING_FACTORS[_ICON_SIZES.index(icon_size)]
    368         icon_spacing = icon_size + style.DEFAULT_SPACING * \
    369             _ICON_SPACING_FACTORS[_ICON_SIZES.index(icon_size)]
     365        if self._spiral_mode:
     366            _icon_spacing_factor = _SPIRAL_SPACING_FACTOR
     367        else:
     368            _icon_spacing_factor = _RING_SPACING_FACTOR
     369
     370        # The diagonal width of an icon is used to help stabilise the
     371        # spacing of icons across a wide range of circle and spiral
     372        # layout sizes:
     373        icon_spacing = math.sqrt(icon_size ** 2 * 2) * _icon_spacing_factor + \
     374            style.DEFAULT_SPACING
    370375        angle = _INITIAL_ANGLE
    371         radius = _MINIMUM_RADIUS - (icon_size * _MIMIMUM_RADIUS_ENCROACHMENT)
     376        radius = _MINIMUM_RADIUS + (icon_spacing *
     377                                    _MIMIMUM_RADIUS_PADDING_FACTOR)
    372378        for i_ in range(icon_count):
    373379            circumference = radius * 2 * math.pi
    374380            n = circumference / icon_spacing
    375381            angle += (2 * math.pi / n)
    376             radius += (float(icon_spacing) * spiral_spacing / n)
     382            radius += (float(icon_spacing) * _RADIUS_GROWTH_FACTOR / n)
    377383        return angle, radius
    378384
    379385    def allocate_children(self, allocation, children):