diff --git a/activities/browser/BrowserActivity.py b/activities/browser/BrowserActivity.py index 6aa58b36..8203a670 100644 --- a/activities/browser/BrowserActivity.py +++ b/activities/browser/BrowserActivity.py @@ -16,6 +16,7 @@ class BrowserActivity(Activity): def __init__(self): Activity.__init__(self) + gtkmozembed.push_startup() gtkmozembed.set_profile_path(env.get_profile_path(), 'gecko') self._share_service = None diff --git a/docs/design.txt b/docs/design.txt index cdc2c6a6..cb2bc6cb 100644 --- a/docs/design.txt +++ b/docs/design.txt @@ -41,3 +41,38 @@ Mesh view eliason marcopg: also important regarding the results: the fill color should be the background color, so they look like outlines, and the line color should be near enough to the background to make them less contrasty. Also, all XOs in the result set should be z-sorted to the front of their groups. That's key. eliason marcopg: The activity icons and XOs are treated separately, so it may be the case that several XOs in a group match the search but the activity their in doesn't, and they would be grayed out independently. eliason marcopg: yes, only the color change. Colored stuff is the result. We don't want to actually make things disappear. + + +Mesh discussion + +eliason marcopg: Well, the terminology we're now using for the zoom level labels is: My Activities, My Friends, My Neighbors. +eliason marcopg: Alright, true, so the working terminology (not the labels for the search field, but still used by all of us) is: home, friends, mesh +eliason marcopg: If you treat each frieeliason marcopg: If you treat each friend or group as a node in a graph, and each edge in the graph as a spring, you can let the system reach an equilibrium using a basic physics simulation that will spread the nodes out evenly.nd or group as a node in a graph, and each edge in the graph as a spring, you can let the system reach an equilibrium using a basic physics simulation that will spread the nodes out evenly. +eliason marcopg: If you treat each friend or group as a node in a graph, and each edge in the graph as a spring, you can let the system reach an equilibrium using a basic physics simulation that will spread the nodes out evenly. +eliason marcopg: There's lots of info on this type of thing online. To do it right within a given box, you also have to add anchored springs at the corners and such to stretch the whole thing out to fill the space. +eliason OK, so another basic idea is to keep a very rough downsampled grayscale image around.... +eliason The grayscale value would map to the number of XOs within the grid cell on screen. +eliason marcopg: Then, when placing a new one you could just find the best place to place it , though now that I think about it that would probably require a simulated annealing algorithm or something else clever to do... +marcopg eliason, do you mean macro cell here? +marcopg i.e. every buddy would be placed in one macro cell +eliason marcopg: Well, actually I guess you'd kind of want a blurred brayscale image, where each object placed represents a white circle, but with a gaussian blur so that it acts like a topographic map of the mesh. +eliason marcopg: The white spots would be dense, like hills, the black spots would be void of people, like holes. Then to place a new one, you kind of roll a simulated marble around until you find a good hole to place it in... +eliason marcopg: And, yet another idea, which could be used in conjunction with or independent of the above. You could simply place a small repulsive force between the objects, so that they push each other apart slightly. You could just place at random and have them adjust accordingly. This works very much like the spring model, though. +eliason Of course, the drawback of the third idea is that it's n^2 in the number of groups on the mesh, but that number should never be that large. +eliason The spring model is a little more complicated, but you only have to place springs between nearby objects, which reduces that somewhat. +eliason marcopg: But actually, I think #3 might be the easiest to implement, and work just as well. It works nicely since it could still allow you to drag them around and the rest of the mesh would react naturally. In the spring model, you'd have to dynamically add and break spring connections when a node is moved around. +marcopg eliason, mm was just thinking about this would interact with custom placed nodes... +marcopg eliason, I never done something similar before so I will really need to play a bit with it... +eliason marcopg: Also, #3 is more forgiving: In the spring model, placing one new node will move EVERY node in the mesh somewhat, if even just a small amount, since the whole system adjusts. With the repulsion force, only nearby nodes would be affected, except of course through a chain reaction... +eliason marcopg: I'm sure we can find documentation. Basically, you calculate the distance between the two nodes (pythag) and if that distance is less than some threshold you compute the angle between them (atan2) and then you give each one a small repulsive acceleration, and update each frame by treating each with its own acceleration, velocity, and position. +eliason marcopg: radiusConstant + (numXos*radiusScale) + ((index%3)*offsetScale) <-- that gets pretty close to what I'm working with now. +eliason marcopg: One addition: When the groups are small, we don't want to add the snowflake effect, since they fit in neat geometric shapes around the ring. So we get....actually, here's the ugly line of code: radius = 25 + .3*(Math.max(participants.length-10,0)) + (i%3)*.5*(Math.max(participants.length-10,0)); +eliason marcopg: The added ugliness is a bit of code that zeros out the 2nd two quantities if there are less than 10 people in the group. You could just place them in an if block actually, but I'd done it this way in case I wanted to change the thresholds independently...eliason marcopg: The added ugliness is a bit of code that zeros out the 2nd two quantities if there are less than 10 people in the group. You could just place them in an if block actually, but I'd done it this way in case I wanted to change the thresholds independently... +eliason marcopg: OK, cool. The animation is a simple easing algorithm: position += (targetPostition - position)*percentage. +eliason marcopg: Well, that's a function of the radius and the angle computed from above. targetX = radius*cos(angle), targetY = radius*sin(angle), for each XO. +marcopg eliason, aaah I see now + +eliason marcopg: The basic problem is that people are crossing an index that is a multiple of the mod, so everyone shifts in and out. What if, instead, we adjusted the indeces of every XO with an index of modValue*c greater than the XO that left, and subtract modValue from each of their indices? +eliason With mod 3, we basically have 3 levels of the ring. This solution would just shift ONE of those rings couter-clockwise one XO position, leaving the other two rings intact as is. We move many fewer XOs than before, but we minimize the movement any given XO has to make by spreading it across the ring level instead of moving the last XO all the way across the circle...eliason marcopg: The basic problem is that people are crossing an index that is a multiple of the mod, so everyone shifts in and out. What if, instead, we adjusted the indeces of every XO with an index of modValue*c greater than the XO that left, and subtract modValue from each of their indices? +eliason With mod 3, we basically have 3 levels of the ring. This solution would just shift ONE of those rings couter-clockwise one XO position, leaving the other two rings intact as is. We move many fewer XOs than before, but we minimize the movement any given XO has to make by spreading it across the ring level instead of moving the last XO all the way across the circle... +eliason marcopg: The final detail of that, beyond shifting each index down by the mod value, is to shift the very last group of people in the ring down to fill all the holes, if you get my meaning... diff --git a/shell/view/BuddyIcon.py b/shell/view/BuddyIcon.py index 607dec65..4fec55b0 100644 --- a/shell/view/BuddyIcon.py +++ b/shell/view/BuddyIcon.py @@ -4,7 +4,7 @@ from view.BuddyMenu import BuddyMenu class BuddyIcon(MenuIcon): def __init__(self, shell, menu_shell, friend): MenuIcon.__init__(self, menu_shell, icon_name='stock-buddy', - color=friend.get_color(), size=96) + color=friend.get_color(), size=112) self._shell = shell self._friend = friend @@ -20,17 +20,19 @@ class BuddyIcon(MenuIcon): def _popup_action_cb(self, popup, action): self.popdown() + model = self._shell.get_model() + + if action == BuddyMenu.ACTION_REMOVE_FRIEND: + friends = model.get_friends() + friends.remove(self._friend) + buddy = self._friend.get_buddy() if buddy == None: return - model = self._shell.get_model() if action == BuddyMenu.ACTION_INVITE: activity = model.get_current_activity() activity.invite(buddy) elif action == BuddyMenu.ACTION_MAKE_FRIEND: friends = model.get_friends() friends.make_friend(buddy) - elif action == BuddyMenu.ACTION_REMOVE_FRIEND: - friends = model.get_friends() - friends.remove(buddy) diff --git a/shell/view/home/FriendsGroup.py b/shell/view/home/FriendsGroup.py index bac8cff6..1c2ea3a8 100644 --- a/shell/view/home/FriendsGroup.py +++ b/shell/view/home/FriendsGroup.py @@ -15,7 +15,7 @@ class FriendsGroup(goocanvas.Group): self._icon_layout = IconLayout(1200, 900) self._friends = {} - me = MyIcon(100) + me = MyIcon(112) me.translate(600 - (me.get_property('size') / 2), 450 - (me.get_property('size') / 2)) self.add_child(me) diff --git a/shell/view/home/MeshGroup.py b/shell/view/home/MeshGroup.py index 61118238..4578a010 100644 --- a/shell/view/home/MeshGroup.py +++ b/shell/view/home/MeshGroup.py @@ -14,7 +14,7 @@ class ActivityItem(IconItem): self._activity = activity IconItem.__init__(self, icon_name=self.get_icon_name(), - color=self.get_color(), size=96) + color=self.get_color(), size=112) def get_id(self): return self._activity.get_id()