diff --git a/.gitignore b/.gitignore index fa8f8702..08da78c4 100644 --- a/.gitignore +++ b/.gitignore @@ -45,7 +45,6 @@ config.sub depcomp libtool ltmain.sh -po/ChangeLog m4/intltool.m4 bindings/globalkeys/globalkeys.c bindings/gecko/gecko.c diff --git a/configure.ac b/configure.ac index 33fb9828..46a0c026 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([Sugar],[0.29],[],[sugar]) +AC_INIT([Sugar],[0.33],[],[sugar]) AC_PREREQ([2.59]) diff --git a/po/ChangeLog b/po/ChangeLog new file mode 100644 index 00000000..e69de29b diff --git a/po/POTFILES.in b/po/POTFILES.in index 59ee6ac8..ac597a6d 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -2,4 +2,4 @@ activities/browser/NavigationToolbar.py sugar/chat/ChatEditor.py activities/chat/ChatActivity.py activities/groupchat/GroupChatActivity.py -shell/FirstTimeDialog.py +shell/view/FirstTimeDialog.py diff --git a/services/presence/Activity.py b/services/presence/Activity.py index a900ea12..e03a98b4 100644 --- a/services/presence/Activity.py +++ b/services/presence/Activity.py @@ -4,8 +4,6 @@ PRESENCE_SERVICE_TYPE = "_presence_olpc._tcp" ACTIVITY_DBUS_OBJECT_PATH = "/org/laptop/Presence/Activities/" ACTIVITY_DBUS_INTERFACE = "org.laptop.Presence.Activity" -class NotFoundError(Exception): - pass class ActivityDBusHelper(dbus.service.Object): def __init__(self, parent, bus_name, object_path): @@ -17,22 +15,16 @@ class ActivityDBusHelper(dbus.service.Object): @dbus.service.method(ACTIVITY_DBUS_INTERFACE, in_signature="s", out_signature="ao") def getServicesOfType(self, stype): - services = self._parent.get_services_of_type(stype) - if not services: - raise NotFoundError("Not found") ret = [] - for serv in services: + for serv in self._parent.get_services_of_type(stype): ret.append(serv.object_path()) return ret @dbus.service.method(ACTIVITY_DBUS_INTERFACE, in_signature="", out_signature="ao") def getServices(self): - services = self._parent.get_services() - if not services: - raise NotFoundError("Not found") ret = [] - for serv in services: + for serv in self._parent.get_services(): ret.append(serv.object_path()) return ret @@ -49,11 +41,8 @@ class ActivityDBusHelper(dbus.service.Object): @dbus.service.method(ACTIVITY_DBUS_INTERFACE, in_signature="", out_signature="ao") def getJoinedBuddies(self): - buddies = self._parent.get_joined_buddies() - if not buddies: - raise NotFoundError("Not found") ret = [] - for buddy in buddies: + for buddy in self._parent.get_joined_buddies(): ret.append(buddy.object_path()) return ret @@ -119,7 +108,7 @@ class Activity(object): def get_services_of_type(self, stype): if self._services.has_key(stype): return self._services[stype] - return None + return [] def get_joined_buddies(self): buddies = [] diff --git a/services/presence/PresenceService.py b/services/presence/PresenceService.py index 400d7cf2..71fd6414 100644 --- a/services/presence/PresenceService.py +++ b/services/presence/PresenceService.py @@ -148,27 +148,24 @@ class PresenceServiceDBusHelper(dbus.service.Object): @dbus.service.method(_PRESENCE_DBUS_INTERFACE, in_signature="", out_signature="ao") def getServices(self): - services = self._parent.get_services() ret = [] - for serv in services: + for serv in self._parent.get_services(): ret.append(serv.object_path()) return ret @dbus.service.method(_PRESENCE_DBUS_INTERFACE, in_signature="s", out_signature="ao") def getServicesOfType(self, stype): - services = self._parent.get_services_of_type(stype) ret = [] - for serv in services: + for serv in self._parent.get_services_of_type(stype): ret.append(serv.object_path()) return ret @dbus.service.method(_PRESENCE_DBUS_INTERFACE, in_signature="", out_signature="ao") def getActivities(self): - activities = self._parent.get_activities() ret = [] - for act in activities: + for act in self._parent.get_activities(): ret.append(act.object_path()) return ret @@ -183,9 +180,8 @@ class PresenceServiceDBusHelper(dbus.service.Object): @dbus.service.method(_PRESENCE_DBUS_INTERFACE, in_signature="", out_signature="ao") def getBuddies(self): - buddies = self._parent.get_buddies() ret = [] - for buddy in buddies: + for buddy in self._parent.get_buddies(): ret.append(buddy.object_path()) return ret @@ -260,7 +256,7 @@ class PresenceServiceDBusHelper(dbus.service.Object): found_serv = serv break if not found_serv: - raise NotFoundError("The activity %s was not found." % service_op) + raise NotFoundError("The service %s was not found." % service_op) return self._parent.unregister_service(found_serv, sender) @dbus.service.method(_PRESENCE_DBUS_INTERFACE, @@ -714,7 +710,7 @@ class PresenceService(object): raise ValueError("invalid activity id") owner_nick = self._owner.get_name() real_name = Service.compose_service_name(owner_nick, activity_id) - if address and isinstance(address, unicode): + if address and not isinstance(address, unicode): raise ValueError("address must be a unicode string.") if address == None and stype.endswith('_udp'): # Use random currently unassigned multicast address diff --git a/shell/view/BuddyIcon.py b/shell/view/BuddyIcon.py index 8f875c96..3dec8d88 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, buddy): MenuIcon.__init__(self, menu_shell, icon_name='stock-buddy', - color=buddy.get_color(), size=112) + color=buddy.get_color()) self._shell = shell self._buddy = buddy diff --git a/shell/view/BuddyMenu.py b/shell/view/BuddyMenu.py index 3b0d69c4..814196ac 100644 --- a/shell/view/BuddyMenu.py +++ b/shell/view/BuddyMenu.py @@ -1,5 +1,6 @@ import gtk import gobject +import hippo from sugar.graphics.menu import Menu from sugar.graphics.canvasicon import CanvasIcon @@ -22,7 +23,7 @@ class BuddyMenu(Menu): scaled_pixbuf = pixbuf.scale_simple(_ICON_SIZE, _ICON_SIZE, gtk.gdk.INTERP_BILINEAR) del pixbuf - icon_item = hippo.Image(pixbuf=scaled_pixbuf) + icon_item = hippo.CanvasImage(pixbuf=scaled_pixbuf) Menu.__init__(self, buddy.get_name(), icon_item) diff --git a/shell/view/Makefile.am b/shell/view/Makefile.am index e1db8698..c3c1bc6e 100644 --- a/shell/view/Makefile.am +++ b/shell/view/Makefile.am @@ -4,10 +4,10 @@ sugardir = $(pkgdatadir)/shell/view sugar_PYTHON = \ __init__.py \ ActivityHost.py \ - BuddyActivityView.py \ ConsoleWindow.py \ FirstTimeDialog.py \ BuddyIcon.py \ BuddyMenu.py \ OverlayWindow.py \ - Shell.py + Shell.py \ + stylesheet.py diff --git a/shell/view/Shell.py b/shell/view/Shell.py index b4f69747..38ba9acb 100644 --- a/shell/view/Shell.py +++ b/shell/view/Shell.py @@ -2,6 +2,8 @@ import gtk import gobject import wnck +import view.stylesheet +from sugar.graphics import style from view.home.HomeWindow import HomeWindow from sugar.presence import PresenceService from view.ActivityHost import ActivityHost @@ -28,6 +30,8 @@ class Shell(gobject.GObject): self._hosts = {} self._screen = wnck.screen_get_default() + style.load_stylesheet(view.stylesheet) + self._key_grabber = KeyGrabber() self._key_grabber.connect('key-pressed', self.__global_key_pressed_cb) diff --git a/shell/view/frame/ActivitiesBox.py b/shell/view/frame/ActivitiesBox.py index d46f3bed..5013a89c 100644 --- a/shell/view/frame/ActivitiesBox.py +++ b/shell/view/frame/ActivitiesBox.py @@ -10,7 +10,7 @@ class ActivityItem(CanvasIcon): def __init__(self, activity): icon_name = activity.get_icon() CanvasIcon.__init__(self, icon_name=icon_name) - style.apply_stylesheet(self, 'frame-activity-icon') + style.apply_stylesheet(self, 'frame.ActivityIcon') self._activity = activity def get_bundle_id(self): diff --git a/shell/view/frame/Frame.py b/shell/view/frame/Frame.py index 9b43fd1c..38f0c682 100644 --- a/shell/view/frame/Frame.py +++ b/shell/view/frame/Frame.py @@ -5,6 +5,7 @@ import wnck from view.frame.ActivitiesBox import ActivitiesBox from view.frame.ZoomBox import ZoomBox +from view.frame.FriendsBox import FriendsBox from view.frame.PanelWindow import PanelWindow from sugar.graphics.timeline import Timeline from sugar.graphics.menushell import MenuShell @@ -143,10 +144,13 @@ class Frame: [x, y] = grid.point(1, 0) bottom_panel.move(box, x, y) - left_panel = self._create_panel(grid, 0, 1, 1, 10) - right_panel = self._create_panel(grid, 15, 1, 1, 10) + box = FriendsBox(self._shell, self._menu_shell) + right_panel.append(box) + + left_panel = self._create_panel(grid, 0, 1, 1, 10) + def _create_panel(self, grid, x, y, width, height): panel = PanelWindow() diff --git a/shell/view/frame/RightPanel.py b/shell/view/frame/FriendsBox.py similarity index 86% rename from shell/view/frame/RightPanel.py rename to shell/view/frame/FriendsBox.py index 366dbfda..8d48a0ec 100644 --- a/shell/view/frame/RightPanel.py +++ b/shell/view/frame/FriendsBox.py @@ -1,15 +1,16 @@ import hippo -from sugar.graphics.CanvasIcon import CanvasIcon +from sugar.graphics.canvasicon import CanvasIcon from sugar.graphics.iconcolor import IconColor +from sugar.graphics import style from sugar.presence import PresenceService from view.BuddyIcon import BuddyIcon from model.BuddyModel import BuddyModel from view.frame.MenuStrategy import MenuStrategy -class RightPanel(hippo.CanvasBox): +class FriendsBox(hippo.CanvasBox): def __init__(self, shell, menu_shell): - CanvasBox.__init__(self) + hippo.CanvasBox.__init__(self) self._shell = shell self._menu_shell = menu_shell self._activity_ps = None @@ -26,18 +27,18 @@ class RightPanel(hippo.CanvasBox): def add(self, buddy): model = BuddyModel(buddy=buddy) icon = BuddyIcon(self._shell, self._menu_shell, model) + style.apply_stylesheet(icon, 'frame.BuddyIcon') icon.set_menu_strategy(MenuStrategy()) - self.append(icon, 0) + self.append(icon) self._buddies[buddy.get_name()] = icon def remove(self, buddy): - i = self.find_child(self._buddies[buddy.get_name()]) - self.remove_child(i) + self.remove(self._buddies[buddy.get_name()]) def clear(self): - while (self.get_n_children() > 0): - self.remove_child(0) + for item in self.get_children(): + self.remove(item) self._buddies = {} def __activity_appeared_cb(self, pservice, activity_ps): diff --git a/shell/view/frame/Makefile.am b/shell/view/frame/Makefile.am index 01458cc9..c2a0b9fb 100644 --- a/shell/view/frame/Makefile.am +++ b/shell/view/frame/Makefile.am @@ -2,7 +2,7 @@ sugardir = $(pkgdatadir)/shell/view/frame sugar_PYTHON = \ __init__.py \ ActivitiesBox.py \ - RightPanel.py \ + FriendsBox.py \ PanelWindow.py \ Frame.py \ ZoomBox.py \ diff --git a/shell/view/frame/MenuStrategy.py b/shell/view/frame/MenuStrategy.py index 0519d234..e95fffcc 100644 --- a/shell/view/frame/MenuStrategy.py +++ b/shell/view/frame/MenuStrategy.py @@ -1,15 +1,39 @@ +import hippo + from sugar.graphics.grid import Grid class MenuStrategy: - def get_menu_position(self, menu, x, y, width, height): - grid = Grid() + def _get_canvas(self, item): + canvas = item + while (not isinstance(canvas, hippo.Canvas)): + canvas = canvas.get_context() + return canvas - [grid_x1, grid_y1] = grid.fit_point(x, y) - [grid_x2, grid_y2] = grid.fit_point(x + width, y + height) + def _get_item_origin(self, canvas, item): + [x, y] = item.get_context().translate_to_widget(item) - menu_grid_x = grid_x1 - menu_grid_y = grid_y2 + [origin_x, origin_y] = canvas.window.get_origin() + x += origin_x + y += origin_y - [menu_x, menu_y] = grid.point(menu_grid_x, menu_grid_y) + return [x, y] + + def get_menu_position(self, menu, item): + canvas = self._get_canvas(item) + + [x, y] = self._get_item_origin(canvas, item) + [width, height] = item.get_allocation() + + [canvas_x, canvas_y] = canvas.window.get_origin() + canvas_rect = canvas.get_allocation() + [menu_w, menu_h] = menu.size_request() + + menu_x = x + menu_y = y + height + + if (menu_x + menu_w > canvas_x) and \ + (menu_y < canvas_y + canvas_rect.height): + menu_x = x - menu_w + menu_y = y return [menu_x, menu_y] diff --git a/shell/view/frame/ZoomBox.py b/shell/view/frame/ZoomBox.py index 7282da78..86b7040b 100644 --- a/shell/view/frame/ZoomBox.py +++ b/shell/view/frame/ZoomBox.py @@ -15,11 +15,9 @@ class ActivityMenu(Menu): Menu.__init__(self, activity_host.get_title()) icon = CanvasIcon(icon_name='stock-share-mesh') - style.apply_stylesheet(icon, 'menu-action-icon') self.add_action(icon, ActivityMenu.ACTION_SHARE) icon = CanvasIcon(icon_name='stock-close') - style.apply_stylesheet(icon, 'menu-action-icon') self.add_action(icon, ActivityMenu.ACTION_CLOSE) class ActivityIcon(MenuIcon): @@ -61,22 +59,22 @@ class ZoomBox(hippo.CanvasBox): self._activity_icon = None icon = CanvasIcon(icon_name='stock-zoom-mesh') - style.apply_stylesheet(icon, 'frame-zoom-icon') + style.apply_stylesheet(icon, 'frame.ZoomIcon') icon.connect('activated', self._level_clicked_cb, sugar.ZOOM_MESH) self.append(icon) icon = CanvasIcon(icon_name='stock-zoom-friends') - style.apply_stylesheet(icon, 'frame-zoom-icon') + style.apply_stylesheet(icon, 'frame.ZoomIcon') icon.connect('activated', self._level_clicked_cb, sugar.ZOOM_FRIENDS) self.append(icon) icon = CanvasIcon(icon_name='stock-zoom-home') - style.apply_stylesheet(icon, 'frame-zoom-icon') + style.apply_stylesheet(icon, 'frame.ZoomIcon') icon.connect('activated', self._level_clicked_cb, sugar.ZOOM_HOME) self.append(icon) icon = CanvasIcon(icon_name='stock-zoom-activity') - style.apply_stylesheet(icon, 'frame-zoom-icon') + style.apply_stylesheet(icon, 'frame.ZoomIcon') icon.connect('activated', self._level_clicked_cb, sugar.ZOOM_ACTIVITY) self.append(icon) @@ -89,7 +87,7 @@ class ZoomBox(hippo.CanvasBox): if activity: icon = ActivityIcon(self._shell, self._menu_shell, activity) - style.apply_stylesheet(icon, 'frame-zoom-icon') + style.apply_stylesheet(icon, 'frame.ZoomIcon') self.append(icon, 0) self._activity_icon = icon else: diff --git a/shell/view/BuddyActivityView.py b/shell/view/home/FriendView.py similarity index 86% rename from shell/view/BuddyActivityView.py rename to shell/view/home/FriendView.py index 93067110..eb967048 100644 --- a/shell/view/BuddyActivityView.py +++ b/shell/view/home/FriendView.py @@ -1,13 +1,14 @@ import hippo import gobject -import BuddyIcon +from view.BuddyIcon import BuddyIcon from sugar.graphics.canvasicon import CanvasIcon +from sugar.graphics import style from sugar.presence import PresenceService import conf -class BuddyActivityView(hippo.CanvasBox): +class FriendView(hippo.CanvasBox): def __init__(self, shell, menu_shell, buddy, **kwargs): hippo.CanvasBox.__init__(self, **kwargs) @@ -15,10 +16,12 @@ class BuddyActivityView(hippo.CanvasBox): self._activity_registry = conf.get_activity_registry() self._buddy = buddy - self._buddy_icon = BuddyIcon.BuddyIcon(shell, menu_shell, buddy) + self._buddy_icon = BuddyIcon(shell, menu_shell, buddy) + style.apply_stylesheet(self._buddy_icon, 'friends.FriendIcon') self.append(self._buddy_icon) - self._activity_icon = CanvasIcon(size=48) + self._activity_icon = CanvasIcon() + style.apply_stylesheet(self._activity_icon, 'friends.ActivityIcon') self._activity_icon_visible = False if self._buddy.is_present(): diff --git a/shell/view/home/FriendsBox.py b/shell/view/home/FriendsBox.py index 53cf8b6b..ed722f47 100644 --- a/shell/view/home/FriendsBox.py +++ b/shell/view/home/FriendsBox.py @@ -1,22 +1,24 @@ import random import hippo +import gobject -from sugar.graphics.spreadlayout import SpreadLayout +from sugar.graphics.spreadbox import SpreadBox +from sugar.graphics import style from view.home.MyIcon import MyIcon -from view.BuddyActivityView import BuddyActivityView +from view.home.FriendView import FriendView -class FriendsBox(hippo.CanvasBox, hippo.CanvasItem): +class FriendsBox(SpreadBox, hippo.CanvasItem): __gtype_name__ = 'SugarFriendsBox' def __init__(self, shell, menu_shell): - hippo.CanvasBox.__init__(self, background_color=0xe2e2e2ff) + SpreadBox.__init__(self, background_color=0xe2e2e2ff) self._shell = shell self._menu_shell = menu_shell - self._layout = SpreadLayout() self._friends = {} - self._my_icon = MyIcon(112) + self._my_icon = MyIcon() + style.apply_stylesheet(self._my_icon, 'friends.MyIcon') self.append(self._my_icon, hippo.PACK_FIXED) friends = self._shell.get_model().get_friends() @@ -27,9 +29,11 @@ class FriendsBox(hippo.CanvasBox, hippo.CanvasItem): friends.connect('friend-added', self._friend_added_cb) friends.connect('friend-removed', self._friend_removed_cb) + gobject.idle_add(self.spread) + def add_friend(self, buddy_info): - icon = BuddyActivityView(self._shell, self._menu_shell, buddy_info) - self.append(icon, hippo.PACK_FIXED) + icon = FriendView(self._shell, self._menu_shell, buddy_info) + self.add(icon) self._friends[buddy_info.get_name()] = icon @@ -41,9 +45,7 @@ class FriendsBox(hippo.CanvasBox, hippo.CanvasItem): del self._friends[name] def do_allocate(self, width, height): - hippo.CanvasBox.do_allocate(self, width, height) - - self._layout.layout(self) + SpreadBox.do_allocate(self, width, height) [icon_width, icon_height] = self._my_icon.get_allocation() self.move(self._my_icon, (width - icon_width) / 2, diff --git a/shell/view/home/HomeBox.py b/shell/view/home/HomeBox.py index ccaa9851..019e4225 100644 --- a/shell/view/home/HomeBox.py +++ b/shell/view/home/HomeBox.py @@ -2,6 +2,8 @@ import hippo from view.home.activitiesdonut import ActivitiesDonut from view.home.MyIcon import MyIcon +from sugar.graphics.grid import Grid +from sugar.graphics import style class HomeBox(hippo.CanvasBox, hippo.CanvasItem): __gtype_name__ = 'SugarHomeBox' @@ -10,10 +12,13 @@ class HomeBox(hippo.CanvasBox, hippo.CanvasItem): hippo.CanvasBox.__init__(self, background_color=0xe2e2e2ff, yalign=2) - donut = ActivitiesDonut(shell, box_width=300, box_height=300) + grid = Grid() + donut = ActivitiesDonut(shell, box_width=grid.dimension(7), + box_height=grid.dimension(7)) self.append(donut) - self._my_icon = MyIcon(120) + self._my_icon = MyIcon() + style.apply_stylesheet(self._my_icon, 'home.MyIcon') self.append(self._my_icon, hippo.PACK_FIXED) def do_allocate(self, width, height): diff --git a/shell/view/home/Makefile.am b/shell/view/home/Makefile.am index 39262012..11e221c3 100644 --- a/shell/view/home/Makefile.am +++ b/shell/view/home/Makefile.am @@ -2,6 +2,7 @@ sugardir = $(pkgdatadir)/shell/view/home sugar_PYTHON = \ __init__.py \ activitiesdonut.py \ + FriendView.py \ FriendsBox.py \ HomeBox.py \ HomeWindow.py \ diff --git a/shell/view/home/MeshBox.py b/shell/view/home/MeshBox.py index 281ddc1a..be47f7e9 100644 --- a/shell/view/home/MeshBox.py +++ b/shell/view/home/MeshBox.py @@ -1,27 +1,27 @@ import random import hippo +import gobject -from sugar.graphics.spreadlayout import SpreadLayout +from sugar.graphics.spreadbox import SpreadBox +from sugar.graphics.snowflakebox import SnowflakeBox from sugar.graphics.canvasicon import CanvasIcon from view.BuddyIcon import BuddyIcon -from sugar.graphics.snowflakelayout import SnowflakeLayout import conf -class ActivityView(hippo.CanvasBox): +class ActivityView(SnowflakeBox): def __init__(self, shell, menu_shell, model): - hippo.CanvasBox.__init__(self) + SnowflakeBox.__init__(self) self._shell = shell self._model = model - self._layout = SnowflakeLayout() self._icons = {} icon = CanvasIcon(icon_name=model.get_icon_name(), color=model.get_color(), size=80) icon.connect('activated', self._clicked_cb) self.append(icon, hippo.PACK_FIXED) - self._layout.set_root(icon) + self.set_root(icon) def has_buddy_icon(self, name): return self._icons.has_key(name) @@ -35,25 +35,19 @@ class ActivityView(hippo.CanvasBox): self.remove(icon) del self._icons[name] - def get_size_request(self): - size = self._layout.get_size() - return [size, size] - def _clicked_cb(self, item): registry = conf.get_activity_registry() default_type = self._model.get_service().get_type() bundle = registry.get_activity_from_type(default_type) self._shell.join_activity(bundle.get_id(), self._model.get_id()) -class MeshBox(hippo.CanvasBox, hippo.CanvasItem): - __gtype_name__ = 'SugarMeshBox' +class MeshBox(SpreadBox): def __init__(self, shell, menu_shell): - hippo.CanvasBox.__init__(self, background_color=0xe2e2e2ff) + SpreadBox.__init__(self, background_color=0xe2e2e2ff) self._shell = shell self._menu_shell = menu_shell self._model = shell.get_model().get_mesh() - self._layout = SpreadLayout() self._buddies = {} self._activities = {} self._buddy_to_activity = {} @@ -71,6 +65,8 @@ class MeshBox(hippo.CanvasBox, hippo.CanvasItem): self._model.connect('activity-added', self._activity_added_cb) self._model.connect('activity-removed', self._activity_removed_cb) + gobject.idle_add(self.spread) + def _buddy_added_cb(self, model, buddy_model): self._add_alone_buddy(buddy_model) @@ -89,7 +85,7 @@ class MeshBox(hippo.CanvasBox, hippo.CanvasItem): def _add_alone_buddy(self, buddy_model): icon = BuddyIcon(self._shell, self._menu_shell, buddy_model) icon.props.size = 80 - self.append(icon, hippo.PACK_FIXED) + self.add(icon) self._buddies[buddy_model.get_name()] = icon @@ -123,7 +119,7 @@ class MeshBox(hippo.CanvasBox, hippo.CanvasItem): def _add_activity(self, activity_model): icon = ActivityView(self._shell, self._menu_shell, activity_model) - self.append(icon, hippo.PACK_FIXED) + self.add(icon) self._activities[activity_model.get_id()] = icon @@ -131,7 +127,3 @@ class MeshBox(hippo.CanvasBox, hippo.CanvasItem): icon = self._activities[activity_model.get_id()] self.remove(icon) del self._activities[activity_model.get_id()] - - def do_allocate(self, width, height): - hippo.CanvasBox.do_allocate(self, width, height) - self._layout.layout(self) diff --git a/shell/view/home/MyIcon.py b/shell/view/home/MyIcon.py index efc5715e..5fccf976 100644 --- a/shell/view/home/MyIcon.py +++ b/shell/view/home/MyIcon.py @@ -1,10 +1,8 @@ from sugar.graphics.canvasicon import CanvasIcon -from sugar.graphics.iconcolor import IconColor import conf class MyIcon(CanvasIcon): - def __init__(self, size): + def __init__(self): profile = conf.get_profile() - CanvasIcon.__init__(self, icon_name='stock-buddy', - color=profile.get_color(), size=size) + color=profile.get_color()) diff --git a/shell/view/home/activitiesdonut.py b/shell/view/home/activitiesdonut.py index b1aaffaa..7c659e76 100644 --- a/shell/view/home/activitiesdonut.py +++ b/shell/view/home/activitiesdonut.py @@ -2,6 +2,7 @@ import hippo import math from sugar.graphics.canvasicon import CanvasIcon +from sugar.graphics import style class ActivitiesDonut(hippo.CanvasBox, hippo.CanvasItem): __gtype_name__ = 'SugarActivitiesDonut' @@ -28,7 +29,8 @@ class ActivitiesDonut(hippo.CanvasBox, hippo.CanvasItem): icon_name = activity.get_icon_name() icon_color = activity.get_icon_color() - icon = CanvasIcon(icon_name=icon_name, color=icon_color, size=75) + icon = CanvasIcon(icon_name=icon_name, color=icon_color) + style.apply_stylesheet(icon, 'ring.ActivityIcon') icon.connect('activated', self.__activity_icon_clicked_cb, activity) self.append(icon, hippo.PACK_FIXED) diff --git a/shell/view/stylesheet.py b/shell/view/stylesheet.py new file mode 100644 index 00000000..a89d1fda --- /dev/null +++ b/shell/view/stylesheet.py @@ -0,0 +1,72 @@ +import gtk +import hippo + +from sugar.graphics.iconcolor import IconColor + +_screen_factor = gtk.gdk.screen_width() / 1200.0 + +_standard_icon_size = int(75.0 * _screen_factor) +_small_icon_size = _standard_icon_size * 0.5 +_medium_icon_size = _standard_icon_size * 1.5 +_large_icon_size = _standard_icon_size * 2.0 +_xlarge_icon_size = _standard_icon_size * 3.0 + +_space_unit = 9 * _screen_factor +_separator_thickness = 3 * _screen_factor + +def _font_description(style, relative_size): + base_size = 18 * _screen_factor + return '%s %dpx' % (style, int(base_size * relative_size)) + +frame_ActivityIcon = { + 'color' : IconColor('white'), + 'size' : _standard_icon_size +} + +frame_ZoomIcon = { + 'size' : _standard_icon_size +} + +frame_BuddyIcon = { + 'size' : _standard_icon_size +} + +menu = { + 'background_color' : 0x000000FF, + 'spacing' : _space_unit, + 'padding' : _space_unit +} + +menu_Title = { + 'color' : 0xFFFFFFFF, + 'font' : _font_description('Bold', 1.2) +} + +menu_Separator = { + 'background_color' : 0xFFFFFFFF, + 'box_height' : _separator_thickness +} + +menu_ActionIcon = { + 'size' : _standard_icon_size +} + +home_MyIcon = { + 'size' : _xlarge_icon_size +} + +ring_ActivityIcon = { + 'size' : _medium_icon_size +} + +friends_MyIcon = { + 'size' : _large_icon_size +} + +friends_FriendIcon = { + 'size' : _large_icon_size +} + +friends_ActivityIcon = { + 'size' : _standard_icon_size +} diff --git a/sugar/graphics/Makefile.am b/sugar/graphics/Makefile.am index fd32797b..aa1f51f7 100644 --- a/sugar/graphics/Makefile.am +++ b/sugar/graphics/Makefile.am @@ -8,7 +8,7 @@ sugar_PYTHON = \ menu.py \ menuicon.py \ menushell.py \ - snowflakelayout.py \ - spreadlayout.py \ + snowflakebox.py \ + spreadbox.py \ style.py \ timeline.py diff --git a/sugar/graphics/__init__.py b/sugar/graphics/__init__.py index b3c54e1e..e69de29b 100644 --- a/sugar/graphics/__init__.py +++ b/sugar/graphics/__init__.py @@ -1,25 +0,0 @@ -import gtk - -from sugar.graphics import style -from sugar.graphics.iconcolor import IconColor - -if gtk.gdk.screen_width() == 1200: - _medium_icon_size = 75 -else: - _medium_icon_size = 50 - -_stylesheet = { - 'color' : IconColor('white'), - 'size' : _medium_icon_size -} -style.register_stylesheet('frame-activity-icon', _stylesheet) - -_stylesheet = { - 'size' : _medium_icon_size -} -style.register_stylesheet('frame-zoom-icon', _stylesheet) - -_stylesheet = { - 'size' : _medium_icon_size -} -style.register_stylesheet('menu-action-icon', _stylesheet) diff --git a/sugar/graphics/grid.py b/sugar/graphics/grid.py index 8d8d2ab2..9a9e96d1 100644 --- a/sugar/graphics/grid.py +++ b/sugar/graphics/grid.py @@ -14,6 +14,9 @@ class Grid(object): return [grid_x * self._factor, grid_y * self._factor, grid_w * self._factor, grid_h * self._factor] + def dimension(self, grid_dimension): + return grid_dimension * self._factor + def fit_point(self, x, y): return [int(x / self._factor), int(y / self._factor)] diff --git a/sugar/graphics/menu.py b/sugar/graphics/menu.py index 9a85bcf4..049dd70e 100644 --- a/sugar/graphics/menu.py +++ b/sugar/graphics/menu.py @@ -3,6 +3,7 @@ import hippo import gobject from sugar.graphics.canvasicon import CanvasIcon +from sugar.graphics import style class Menu(gtk.Window): __gsignals__ = { @@ -17,11 +18,12 @@ class Menu(gtk.Window): self.add(canvas) canvas.show() - self._root = hippo.CanvasBox(background_color=0x000000FF, - spacing=6) + self._root = hippo.CanvasBox() + style.apply_stylesheet(self._root, 'menu') canvas.set_root(self._root) - text = hippo.CanvasText(text=title, color=0xFFFFFFFF) + text = hippo.CanvasText(text=title) + style.apply_stylesheet(text, 'menu.Title') self._root.append(text) if content_box: @@ -29,6 +31,14 @@ class Menu(gtk.Window): self._root.append(separator) self._root.append(content_box) + self._action_box = None + + def _create_separator(self): + separator = hippo.CanvasBox() + style.apply_stylesheet(separator, 'menu.Separator') + return separator + + def _create_action_box(self): separator = self._create_separator() self._root.append(separator) @@ -36,13 +46,11 @@ class Menu(gtk.Window): orientation=hippo.ORIENTATION_HORIZONTAL) self._root.append(self._action_box) - def _create_separator(self): - separator = hippo.CanvasBox(background_color=0xFFFFFFFF, - border_left=6, border_right=6, - box_height=2) - return separator - def add_action(self, icon, action_id): + if not self._action_box: + self._create_action_box() + + style.apply_stylesheet(icon, 'menu.ActionIcon') icon.connect('activated', self._action_clicked_cb, action_id) self._action_box.append(icon) diff --git a/sugar/graphics/menuicon.py b/sugar/graphics/menuicon.py index 3f6d4771..f9c6aa85 100644 --- a/sugar/graphics/menuicon.py +++ b/sugar/graphics/menuicon.py @@ -4,8 +4,8 @@ import gobject from sugar.graphics.canvasicon import CanvasIcon class _MenuStrategy: - def get_menu_position(self, menu, x1, y1, x2, y2): - return [x1, y1] + def get_menu_position(self, menu, item): + return item.get_context().translate_to_widget(item) class MenuIcon(CanvasIcon): def __init__(self, menu_shell, **kwargs): @@ -29,7 +29,7 @@ class MenuIcon(CanvasIcon): def set_menu_strategy(self, strategy): self._menu_strategy = strategy - def _popup(self, x1, y1, x2, y2): + def _popup(self): self.popdown() self._menu_shell.set_active(None) @@ -41,7 +41,7 @@ class MenuIcon(CanvasIcon): self._menu_leave_notify_event_cb) strategy = self._menu_strategy - [x, y] = strategy.get_menu_position(self._menu, x1, y1, x2, y2) + [x, y] = strategy.get_menu_position(self._menu, self) self._menu.move(x, y) self._menu.show() @@ -73,11 +73,7 @@ class MenuIcon(CanvasIcon): def _motion_notify_enter(self): self._stop_popdown_timeout() - - [x, y] = self.get_context().translate_to_widget(self) - [width, height] = self.get_allocation() - - self._popup(x, y, width, height) + self._popup() def _motion_notify_leave(self): self._start_popdown_timeout() diff --git a/sugar/graphics/snowflakebox.py b/sugar/graphics/snowflakebox.py new file mode 100644 index 00000000..86831f7b --- /dev/null +++ b/sugar/graphics/snowflakebox.py @@ -0,0 +1,71 @@ +import math + +import cairo +import hippo + +_BASE_RADIUS = 65 +_CHILDREN_FACTOR = 1 +_FLAKE_DISTANCE = 6 + +class SnowflakeBox(hippo.CanvasBox, hippo.CanvasItem): + __gtype_name__ = 'SugarSnowflakeBox' + def __init__(self, **kwargs): + hippo.CanvasBox.__init__(self, **kwargs) + + self._root = None + self._r = 0 + + def set_root(self, icon): + self._root = icon + + def _layout_root(self): + [width, height] = self._root.get_allocation() + + x = self._cx - (width / 2) + y = self._cy - (height / 2) + + self.move(self._root, int(x), int(y)) + + def _layout_child(self, child, index): + r = self._r + if (len(self.get_children()) > 10): + r += _FLAKE_DISTANCE * (index % 3) + + angle = 2 * math.pi / len(self.get_children()) * index + + [width, height] = child.get_allocation() + x = self._cx + math.cos(angle) * r - (width / 2) + y = self._cy + math.sin(angle) * r - (height / 2) + + self.move(child, int(x), int(y)) + + def do_get_width_request(self): + hippo.CanvasBox.do_get_width_request(self) + + max_child_size = 0 + for child in self.get_children(): + width = child.get_width_request() + height = child.get_height_request(width) + max_child_size = max (max_child_size, width) + max_child_size = max (max_child_size, height) + + return self._r * 2 + max_child_size + _FLAKE_DISTANCE * 2 + + def do_get_height_request(self, width): + hippo.CanvasBox.do_get_height_request(self, width) + return width + + def do_allocate(self, width, height): + hippo.CanvasBox.do_allocate(self, width, height) + + self._cx = width / 2 + self._cy = height / 2 + self._r = _BASE_RADIUS + _CHILDREN_FACTOR * len(self.get_children()) + + self._layout_root() + + index = 0 + for child in self.get_children(): + if child != self._root: + self._layout_child(child, index) + index += 1 diff --git a/sugar/graphics/snowflakelayout.py b/sugar/graphics/snowflakelayout.py deleted file mode 100644 index 611ecaa3..00000000 --- a/sugar/graphics/snowflakelayout.py +++ /dev/null @@ -1,71 +0,0 @@ -import math - -import cairo - -class SnowflakeLayout: - _BASE_RADIUS = 65 - _CHILDREN_FACTOR = 1 - _FLAKE_DISTANCE = 6 - - def __init__(self): - self._root = None - self._children = [] - self._r = 0 - - def set_root(self, icon): - self._root = icon - - def add_child(self, icon): - self._children.append(icon) - self._layout() - - def remove_child(self, icon): - self._children.remove(icon) - self._layout() - - def _layout_root(self): - [width, height] = self._root.get_size_request() - - matrix = cairo.Matrix(1, 0, 0, 1, 0, 0) - matrix.translate(self._cx - (width / 2), self._cy - (height / 2)) - self._root.set_transform(matrix) - - def _layout_child(self, child, index): - r = self._r - if (len(self._children) > 10): - r += SnowflakeLayout._FLAKE_DISTANCE * (index % 3) - - angle = 2 * math.pi / len(self._children) * index - - [width, height] = child.get_size_request() - x = self._cx + math.cos(angle) * r - (width / 2) - y = self._cy + math.sin(angle) * r - (height / 2) - - matrix = cairo.Matrix(1, 0, 0, 1, 0, 0) - matrix.translate(x, y) - child.set_transform(matrix) - - def get_size(self): - max_child_size = 0 - for child in self._children: - [width, height] = child.get_size_request() - max_child_size = max (max_child_size, width) - max_child_size = max (max_child_size, height) - - return self._r * 2 + max_child_size + \ - SnowflakeLayout._FLAKE_DISTANCE * 2 - - def _layout(self): - self._r = SnowflakeLayout._BASE_RADIUS + \ - SnowflakeLayout._CHILDREN_FACTOR * len(self._children) - - size = self.get_size() - self._cx = size / 2 - self._cy = size / 2 - - self._layout_root() - - index = 0 - for child in self._children: - self._layout_child(child, index) - index += 1 diff --git a/sugar/graphics/spreadbox.py b/sugar/graphics/spreadbox.py new file mode 100644 index 00000000..b9d07d45 --- /dev/null +++ b/sugar/graphics/spreadbox.py @@ -0,0 +1,101 @@ +import random +import math + +import cairo +import hippo + +_DISTANCE_THRESHOLD = 120.0 + +class SpreadBox(hippo.CanvasBox, hippo.CanvasItem): + __gtype_name__ = 'SugarSpreadBox' + + def __init__(self, **kwargs): + hippo.CanvasBox.__init__(self, **kwargs) + + self._items_to_position = [] + self._spread_on_add = False + self._stable = False + + def add(self, item): + self._items_to_position.append(item) + self.append(item, hippo.PACK_FIXED) + if self._spread_on_add: + self.spread() + + def spread(self): + self._spread_on_add = True + + [width, height] = self.get_allocation() + for item in self._items_to_position: + x = int(random.random() * width) + y = int(random.random() * height) + + [x, y] = self._clamp_position(item, x, y) + self.move(item, x, y) + + self._items_to_position = [] + + def _get_distance(self, icon1, icon2): + [icon1_x, icon1_y] = self.get_position(icon1) + [icon2_x, icon2_y] = self.get_position(icon2) + + a = icon1_x - icon2_x + b = icon1_y - icon2_y + + return math.sqrt(a * a + b * b) + + def _get_repulsion(self, icon1, icon2): + [icon1_x, icon1_y] = self.get_position(icon1) + [icon2_x, icon2_y] = self.get_position(icon2) + + f_x = icon1_x - icon2_x + f_y = icon1_y - icon2_y + + return [f_x, f_y] + + def _clamp_position(self, icon, x, y): + x = max(0, x) + y = max(0, y) + + item_w = icon.get_width_request() + item_h = icon.get_height_request(item_w) + [box_w, box_h] = self.get_allocation() + + x = min(box_w - item_w, x) + y = min(box_h - item_h, y) + + return [x, y] + + def _spread_icons(self): + self._stable = True + + for icon1 in self.get_children(): + vx = 0 + vy = 0 + + for icon2 in self.get_children(): + if icon1 != icon2: + distance = self._get_distance(icon1, icon2) + if distance <= _DISTANCE_THRESHOLD: + self._stable = False + [f_x, f_y] = self._get_repulsion(icon1, icon2) + vx += f_x + vy += f_y + + if vx != 0 or vy != 0: + [x, y] = self.get_position(icon1) + new_x = x + vx + new_y = y + vy + + [new_x, new_y] = self._clamp_position(icon1, new_x, new_y) + + self.move(icon1, new_x, new_y) + + def do_allocate(self, width, height): + hippo.CanvasBox.do_allocate(self, width, height) + + tries = 10 + self._spread_icons() + while not self._stable and tries > 0: + self._spread_icons() + tries -= 1 diff --git a/sugar/graphics/spreadlayout.py b/sugar/graphics/spreadlayout.py deleted file mode 100644 index 48338c6d..00000000 --- a/sugar/graphics/spreadlayout.py +++ /dev/null @@ -1,76 +0,0 @@ -import random -import math - -import cairo - -class SpreadLayout: - DISTANCE_THRESHOLD = 120.0 - - def __init__(self): - pass - - def _get_distance(self, icon1, icon2): - [icon1_x, icon1_y] = self._constraints[icon1] - [icon2_x, icon2_y] = self._constraints[icon2] - - a = icon1_x - icon2_x - b = icon1_y - icon2_y - - return math.sqrt(a * a + b * b) - - def _get_repulsion(self, icon1, icon2): - [icon1_x, icon1_y] = self._constraints[icon1] - [icon2_x, icon2_y] = self._constraints[icon2] - - f_x = icon1_x - icon2_x - f_y = icon1_y - icon2_y - - return [f_x, f_y] - - def _spread_icons(self): - self._stable = True - - for icon1 in self._icons: - vx = 0 - vy = 0 - - [x, y] = self._constraints[icon1] - - for icon2 in self._icons: - if icon1 != icon2: - distance = self._get_distance(icon1, icon2) - if distance <= IconLayout.DISTANCE_THRESHOLD: - self._stable = False - [f_x, f_y] = self._get_repulsion(icon1, icon2) - vx += f_x - vy += f_y - - new_x = x + vx - new_y = y + vy - - new_x = max(self._x1, new_x) - new_y = max(self._y1, new_y) - - [width, height] = icon1.get_size_request() - new_x = min(self._x2 - width, new_x) - new_y = min(self._y2 - height, new_y) - - self._constraints[icon1] = [new_x, new_y] - - matrix = cairo.Matrix(1, 0, 0, 1, 0, 0) - matrix.translate(new_x - (width / 2), new_y - (height / 2)) - icon1.set_transform(matrix) - - def update(self): - tries = 10 - self._spread_icons() - while not self._stable and tries > 0: - self._spread_icons() - tries -= 1 - - def layout(self, box): - [width, height] = box.get_allocation() - for item in box.get_children(): - x = int(random.random() * width) - y = int(random.random() * height) - box.move(item, x, y) diff --git a/sugar/graphics/style.py b/sugar/graphics/style.py index 4b1bc536..ae1e4246 100644 --- a/sugar/graphics/style.py +++ b/sugar/graphics/style.py @@ -1,5 +1,12 @@ _styles = {} +def load_stylesheet(module): + for objname in dir(module): + if not objname.startswith('_'): + obj = getattr(module, objname) + if isinstance(obj, dict): + register_stylesheet(objname.replace('_', '.'), obj) + def register_stylesheet(name, style): _styles[name] = style diff --git a/sugar/logger.py b/sugar/logger.py index f41d48fd..bdfc2e78 100644 --- a/sugar/logger.py +++ b/sugar/logger.py @@ -12,6 +12,8 @@ if dbus.version < (0, 70, 0): import gobject +from sugar import env + __queue = None CONSOLE_BUS_NAME = 'org.laptop.Sugar.Console' @@ -121,7 +123,9 @@ def start(console_id, console = None): root_logger = logging.getLogger('') root_logger.setLevel(logging.DEBUG) root_logger.addHandler(Handler(queue)) - fileh = logging.FileHandler('/tmp/sugar.log') + + log_file = os.path.join(env.get_profile_path(), 'sugar.log') + fileh = logging.FileHandler(log_file) fileh.setFormatter(logging.Formatter("""[%(asctime)s] %(message)s""")) root_logger.addHandler(fileh) diff --git a/sugar/session/MatchboxProcess.py b/sugar/session/MatchboxProcess.py index fccf47a1..4fd47417 100644 --- a/sugar/session/MatchboxProcess.py +++ b/sugar/session/MatchboxProcess.py @@ -9,6 +9,7 @@ class MatchboxProcess(Process): options = '-kbdconfig %s ' % kbd_config options += '-use_titlebar no ' + options += '-theme olpc ' command = 'matchbox-window-manager %s ' % options Process.__init__(self, command) diff --git a/tests/test-icon-layout.py b/tests/test-icon-layout.py deleted file mode 100755 index 45ea3857..00000000 --- a/tests/test-icon-layout.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/python -import pygtk -pygtk.require('2.0') -import gobject - -from sugar.session.UITestSession import UITestSession - -session = UITestSession() -session.start() - -import sys -import random - -import gtk -import goocanvas - -from view.home.IconLayout import IconLayout -from sugar.graphics import IconColor -from sugar.graphics.IconItem import IconItem -from sugar.graphics.CanvasView import CanvasView -from sugar.graphics.Grid import Grid - -def _create_icon(): - color = IconColor.IconColor() - - icon = IconItem(size=125, color=color, - icon_name='stock-buddy') - root.add_child(icon) - - icon_layout.add_icon(icon) - - return (root.get_n_children() < 20) - -window = gtk.Window() -window.connect("destroy", lambda w: gtk.main_quit()) -window.show() - -canvas = CanvasView() -canvas.show() -window.add(canvas) - -canvas_model = goocanvas.CanvasModelSimple() -root = canvas_model.get_root_item() - -item = goocanvas.Rect(x=0, y=0, width=1200, height=900, - line_width=0.0, fill_color='#e2e2e2') -root.add_child(item) - -icon_layout = IconLayout(Grid()) - -gobject.timeout_add(500, _create_icon) - -canvas.set_model(canvas_model) - -gtk.main() diff --git a/tests/test-spread-box.py b/tests/test-spread-box.py new file mode 100755 index 00000000..6a81834b --- /dev/null +++ b/tests/test-spread-box.py @@ -0,0 +1,45 @@ +#!/usr/bin/python +import pygtk +pygtk.require('2.0') +import gobject + +from sugar.session.UITestSession import UITestSession + +session = UITestSession() +session.start() + +import sys +import random + +import gtk +import hippo + +from sugar.graphics.spreadbox import SpreadBox +from sugar.graphics.iconcolor import IconColor +from sugar.graphics.canvasicon import CanvasIcon + +def _create_icon(): + color = IconColor() + + icon = CanvasIcon(size=100, color=color, + icon_name='stock-buddy') + box.add(icon) + + return (len(box.get_children()) < 20) + +window = gtk.Window() +window.connect("destroy", lambda w: gtk.main_quit()) +window.show() + +canvas = hippo.Canvas() + +box = SpreadBox(background_color=0xe2e2e2ff) +canvas.set_root(box) +box.spread() + +canvas.show() +window.add(canvas) + +gobject.timeout_add(500, _create_icon) + +gtk.main()