Ticket #2143: 0001-adding-spiral-extension-to-Ring-View.patch

File 0001-adding-spiral-extension-to-Ring-View.patch, 7.3 KB (added by walter, 14 years ago)

final version of the patch

  • src/jarabe/desktop/favoriteslayout.py

    From 1452826b50dc2dc0bb9c6bc0b856691e62ee485b Mon Sep 17 00:00:00 2001
    From: Walter Bender <walter@sugarlabs.org>
    Date: Wed, 18 Aug 2010 09:17:25 -0400
    Subject: [PATCH] adding spiral extension to Ring View
    
    ---
     src/jarabe/desktop/favoriteslayout.py |   99 ++++++++++++++++++++++++++-------
     1 files changed, 78 insertions(+), 21 deletions(-)
    
    diff --git a/src/jarabe/desktop/favoriteslayout.py b/src/jarabe/desktop/favoriteslayout.py
    index 85e1b59..7b847ac 100644
    a b  
    11# Copyright (C) 2008 One Laptop Per Child
     2# Copyright (C) 2010 Sugar Labs
    23#
    34# This program is free software; you can redistribute it and/or modify
    45# it under the terms of the GNU General Public License as published by
    _logger = logging.getLogger('FavoritesLayout') 
    3233
    3334_CELL_SIZE = 4
    3435_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]
     42
    3543
    3644class FavoritesLayout(gobject.GObject, hippo.CanvasLayout):
    3745    """Base class of the different layout types."""
    _MINIMUM_RADIUS = style.XLARGE_ICON_SIZE / 2 + style.DEFAULT_SPACING + \ 
    185193        style.STANDARD_ICON_SIZE * 2
    186194_MAXIMUM_RADIUS = (gtk.gdk.screen_height() - style.GRID_CELL_SIZE) / 2 - \
    187195        style.STANDARD_ICON_SIZE - style.DEFAULT_SPACING
     196_ICON_SPACING_FACTORS = [1.5, 1.4, 1.3, 1.2, 1.1, 1.0]
     197_SPIRAL_SPACING_FACTORS = [1.5, 1.5, 1.5, 1.4, 1.3, 1.2]
     198_MIMIMUM_RADIUS_ENCROACHMENT = 0.75
     199_INITIAL_ANGLE = math.pi
     200
    188201
    189202class RingLayout(FavoritesLayout):
    190     """Lay out icons in a ring around the XO man."""
     203    """Lay out icons in a ring or spiral around the XO man."""
    191204
    192205    __gtype_name__ = 'RingLayout'
    193206    icon_name = 'view-radial'
    class RingLayout(FavoritesLayout): 
    201214    def __init__(self):
    202215        FavoritesLayout.__init__(self)
    203216        self._locked_children = {}
     217        self._spiral_mode = False
    204218
    205219    def append(self, icon, locked=False):
    206220        FavoritesLayout.append(self, icon, locked)
    class RingLayout(FavoritesLayout): 
    221235            self._locked_children[child] = (x, y)
    222236
    223237    def _calculate_radius_and_icon_size(self, children_count):
    224         # what's the radius required without downscaling?
    225         distance = style.STANDARD_ICON_SIZE + style.DEFAULT_SPACING
     238        """ Adjust the ring or spiral radius and icon size as needed. """
     239        self._spiral_mode = False
     240        distance = style.MEDIUM_ICON_SIZE + style.DEFAULT_SPACING * \
     241            _ICON_SPACING_FACTORS[_ICON_SIZES.index(style.MEDIUM_ICON_SIZE)]
     242        radius = max(children_count * distance / (2 * math.pi), _MINIMUM_RADIUS)
     243        if radius < _MAXIMUM_RADIUS:
     244            return radius, style.MEDIUM_ICON_SIZE
     245
     246        distance = style.STANDARD_ICON_SIZE + style.DEFAULT_SPACING * \
     247            _ICON_SPACING_FACTORS[_ICON_SIZES.index(style.STANDARD_ICON_SIZE)]
     248        radius = max(children_count * distance / (2 * math.pi), _MINIMUM_RADIUS)
     249        if radius < _MAXIMUM_RADIUS:
     250            return radius, style.STANDARD_ICON_SIZE
     251
     252        self._spiral_mode = True
    226253        icon_size = style.STANDARD_ICON_SIZE
    227         # circumference is 2*pi*r; we want this to be at least
    228         # 'children_count * distance'
    229         radius = children_count * distance / (2 * math.pi)
    230         # limit computed radius to reasonable bounds.
    231         radius = max(radius, _MINIMUM_RADIUS)
    232         radius = min(radius, _MAXIMUM_RADIUS)
    233         # recompute icon size from limited radius
    234         if children_count > 0:
    235             icon_size = (2 * math.pi * radius / children_count) \
    236                         - style.DEFAULT_SPACING
    237         # limit adjusted icon size.
    238         icon_size = max(icon_size, style.SMALL_ICON_SIZE)
    239         icon_size = min(icon_size, style.MEDIUM_ICON_SIZE)
     254        angle, radius = self._calculate_angle_and_radius(children_count,
     255                                                               icon_size)
     256        while radius > _MAXIMUM_RADIUS:
     257            i = _ICON_SIZES.index(icon_size)
     258            if i < len(_ICON_SIZES) - 1:
     259                icon_size = _ICON_SIZES[i + 1]
     260                angle, radius = self._calculate_angle_and_radius(
     261                    children_count, icon_size)
     262            else:
     263                break
    240264        return radius, icon_size
    241265
    242     def _calculate_position(self, radius, icon_size, index, children_count,
     266    def _calculate_position(self, radius, icon_size, icon_index, children_count,
    243267                            sin=math.sin, cos=math.cos):
     268        """ Calculate an icon position on a circle or a spiral. """
    244269        width, height = self.box.get_allocation()
    245         angle = index * (2 * math.pi / children_count) - math.pi / 2
    246         x = radius * cos(angle) + (width - icon_size) / 2
    247         y = radius * sin(angle) + (height - icon_size -
    248                                    (style.GRID_CELL_SIZE/2) ) / 2
     270        if self._spiral_mode:
     271            min_width_, box_width = self.box.get_width_request()
     272            min_height_, box_height = self.box.get_height_request(box_width)
     273            angle, radius = self._calculate_angle_and_radius(icon_index,
     274                                                             icon_size)
     275            x, y = self._convert_from_polar_to_cartesian(angle, radius,
     276                                                         icon_size,
     277                                                         width, height)
     278        else:
     279            angle = icon_index * (2 * math.pi / children_count) - math.pi / 2
     280            x = radius * cos(angle) + (width - icon_size) / 2
     281            y = radius * sin(angle) + (height - icon_size - \
     282                                       (style.GRID_CELL_SIZE / 2)) / 2
     283        return x, y
     284
     285    def _convert_from_polar_to_cartesian(self, angle, radius, icon_size, width,
     286                                         height):
     287        """ Convert angle, radius to x, y """
     288        x = int(math.sin(angle) * radius)
     289        y = int(math.cos(angle) * radius)
     290        x = - x + (width - icon_size) / 2
     291        y = y + (height - icon_size - (style.GRID_CELL_SIZE / 2)) / 2
    249292        return x, y
    250293
     294    def _calculate_angle_and_radius(self, icon_count, icon_size):
     295        """ Based on icon_count and icon_size, calculate radius and angle. """
     296        spiral_spacing = _SPIRAL_SPACING_FACTORS[_ICON_SIZES.index(icon_size)]
     297        icon_spacing = icon_size + style.DEFAULT_SPACING * \
     298            _ICON_SPACING_FACTORS[_ICON_SIZES.index(icon_size)]
     299        angle = _INITIAL_ANGLE
     300        radius = _MINIMUM_RADIUS - (icon_size * _MIMIMUM_RADIUS_ENCROACHMENT)
     301        for i in range(icon_count):
     302            circumference = radius * 2 * math.pi
     303            n = circumference / icon_spacing
     304            angle += (2 * math.pi / n)
     305            radius += (float(icon_spacing) * spiral_spacing / n)
     306        return angle, radius
     307
    251308    def _get_children_in_ring(self):
    252309        children_in_ring = [child for child in self.box.get_layout_children() \
    253310                if child not in self._locked_children]