[PATCH] adding spiral to circle view

Walter Bender walter at sugarlabs.org
Fri Aug 6 08:53:10 EDT 2010


---
 src/jarabe/desktop/favoriteslayout.py |   92 ++++++++++++++++++++++++++-------
 1 files changed, 73 insertions(+), 19 deletions(-)

diff --git a/src/jarabe/desktop/favoriteslayout.py
b/src/jarabe/desktop/favoriteslayout.py
index 85e1b59..a945c49 100644
--- a/src/jarabe/desktop/favoriteslayout.py
+++ b/src/jarabe/desktop/favoriteslayout.py
@@ -1,4 +1,5 @@
 # Copyright (C) 2008 One Laptop Per Child
+# Copyright (C) 2010 Sugar Labs
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -201,6 +202,11 @@ class RingLayout(FavoritesLayout):
     def __init__(self):
         FavoritesLayout.__init__(self)
         self._locked_children = {}
+        self._spiral = False
+        self._radius = _MINIMUM_RADIUS
+        self._orientation = math.pi
+        self._icon_size = style.STANDARD_ICON_SIZE
+        self._count = -1

     def append(self, icon, locked=False):
         FavoritesLayout.append(self, icon, locked)
@@ -221,31 +227,79 @@ class RingLayout(FavoritesLayout):
             self._locked_children[child] = (x, y)

     def _calculate_radius_and_icon_size(self, children_count):
-        # what's the radius required without downscaling?
+        """ determine if we are drawing a circle or a spiral """
         distance = style.STANDARD_ICON_SIZE + style.DEFAULT_SPACING
-        icon_size = style.STANDARD_ICON_SIZE
-        # circumference is 2*pi*r; we want this to be at least
-        # 'children_count * distance'
+
         radius = children_count * distance / (2 * math.pi)
-        # limit computed radius to reasonable bounds.
-        radius = max(radius, _MINIMUM_RADIUS)
-        radius = min(radius, _MAXIMUM_RADIUS)
-        # recompute icon size from limited radius
-        if children_count > 0:
-            icon_size = (2 * math.pi * radius / children_count) \
-                        - style.DEFAULT_SPACING
-        # limit adjusted icon size.
-        icon_size = max(icon_size, style.SMALL_ICON_SIZE)
-        icon_size = min(icon_size, style.MEDIUM_ICON_SIZE)
-        return radius, icon_size
+        if radius < _MAXIMUM_RADIUS:
+            self._spiral = False
+            self._icon_size = style.STANDARD_ICON_SIZE
+        else:
+            self._spiral = True
+            radius = _MINIMUM_RADIUS
+
+        # If there are fewer children, try increasing icon_size.
+        if self._count > children_count:
+            logging.debug('resetting count: %d > %d' % (self._count,
children_count))
+            if self._icon_size == style.MEDIUM_ICON_SIZE:
+                self._icon_size = style.STANDARD_ICON_SIZE
+            elif self._icon_size == style.SMALL_ICON_SIZE:
+                self._icon_size = style.MEDIUM_ICON_SIZE
+        self._count = children_count
+
+        return radius, self._icon_size
+
+    def _calculate_xy(self, icon_size, width, height):
+        """ Convert r, o to x, y """
+        x = -math.sin(self._orientation) * self._radius
+        y = math.cos(self._orientation) * self._radius
+        self._calculate_new_radius_orientation(icon_size +\
+                                                   style.DEFAULT_SPACING)
+
+        x = int(x) + (width - icon_size) / 2
+        y = int(y) + (height - icon_size - (style.GRID_CELL_SIZE / 2) ) / 2
+        return x, y
+
+    def _calculate_new_radius_orientation(self, icon_size):
+        """ Based upon current radius, calculate new increments """
+        circumference = self._radius * 2 * math.pi
+        n = circumference / icon_size
+        self._orientation += 2 * math.pi / n
+        self._radius += float(icon_size) / n

     def _calculate_position(self, radius, icon_size, index, children_count,
                             sin=math.sin, cos=math.cos):
+        """ Try fitting a circle or a spiral """
+
         width, height = self.box.get_allocation()
-        angle = index * (2 * math.pi / children_count) - math.pi / 2
-        x = radius * cos(angle) + (width - icon_size) / 2
-        y = radius * sin(angle) + (height - icon_size -
-                                   (style.GRID_CELL_SIZE/2) ) / 2
+        if not self._spiral:
+            angle = index * (2 * math.pi / children_count) - math.pi / 2
+            x = radius * cos(angle) + (width - icon_size) / 2
+            y = radius * sin(angle) + (height - icon_size -
+                                       (style.GRID_CELL_SIZE/2) ) / 2
+        else:
+            min_width_, box_width = self.box.get_width_request()
+            min_height_, box_height = self.box.get_height_request(box_width)
+            if index == 0:
+                self._radius = _MINIMUM_RADIUS
+                self._orientation = math.pi
+            x, y = self._calculate_xy(icon_size, width, height)
+            # If we run off the edge, keep spiraling until we return.
+            while x < min_width_ or x > box_width - icon_size or \
+                    y < min_height_ or y > box_height - icon_size:
+                x, y = self._calculate_xy(icon_size, width, height)
+                # If we run past a corner, we will never return, so time to
+                # shrink the icons.
+                if (x < min_height_ and \
+                        (y < min_width_ or y > box_height - icon_size)) or \
+                   (x > box_width - icon_size and \
+                             (y < min_width_ or y > box_height - icon_size)):
+                    if self._icon_size == style.STANDARD_ICON_SIZE:
+                        self._icon_size = style.MEDIUM_ICON_SIZE
+                    elif self._icon_size == style.MEDIUM_ICON_SIZE:
+                        self._icon_size = style.SMALL_ICON_SIZE
+                    else: # give up
+                        return x, y
         return x, y

     def _get_children_in_ring(self):
-- 
1.7.0.4

-walter

-- 
Walter Bender
Sugar Labs
http://www.sugarlabs.org


More information about the Sugar-devel mailing list