From 72832e01743c9676442e2a46cfa79dbc56aba3a7 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 30 Oct 2006 03:42:51 +0000 Subject: Convert to an ugly Hippo menu --- (limited to 'services/nm') diff --git a/services/nm/Makefile.am b/services/nm/Makefile.am index 6dc19ec..7f6dce8 100644 --- a/services/nm/Makefile.am +++ b/services/nm/Makefile.am @@ -2,7 +2,8 @@ sugardir = $(pkgdatadir)/services/nm sugar_PYTHON = \ __init__.py \ nmclient.py \ - nminfo.py + nminfo.py \ + bubble.py bin_SCRIPTS = sugar-nm-applet diff --git a/services/nm/bubble.py b/services/nm/bubble.py new file mode 100644 index 0000000..ca900db --- /dev/null +++ b/services/nm/bubble.py @@ -0,0 +1,85 @@ +# Copyright (C) 2006, Red Hat, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +import math + +import gobject +import gtk +import hippo + +class Bubble(hippo.CanvasBox, hippo.CanvasItem): + __gtype_name__ = 'NetworkBubble' + + __gproperties__ = { + 'color' : (object, None, None, + gobject.PARAM_READWRITE), + 'percent' : (object, None, None, + gobject.PARAM_READWRITE), + } + + def __init__(self, **kwargs): + self._color = None + self._percent = 0 + self._radius = 8 + + hippo.CanvasBox.__init__(self, **kwargs) + + def do_set_property(self, pspec, value): + if pspec.name == 'color': + self._color = value + self.emit_paint_needed(0, 0, -1, -1) + elif pspec.name == 'percent': + self._percent = value + self.emit_paint_needed(0, 0, -1, -1) + + def do_get_property(self, pspec): + if pspec.name == 'color': + return self._color + elif pspec.name == 'percent': + return self._percent + + def _string_to_rgb(self, color_string): + col = gtk.gdk.color_parse(color_string) + return (col.red / 65535.0, col.green / 65535.0, col.blue / 65535.0) + + def do_paint_below_children(self, cr, damaged_box): + [width, height] = self.get_allocation() + + line_width = 3.0 + x = line_width + y = line_width + width -= line_width * 2 + height -= line_width * 2 + + cr.move_to(x + self._radius, y); + cr.arc(x + width - self._radius, y + self._radius, + self._radius, math.pi * 1.5, math.pi * 2); + cr.arc(x + width - self._radius, x + height - self._radius, + self._radius, 0, math.pi * 0.5); + cr.arc(x + self._radius, y + height - self._radius, + self._radius, math.pi * 0.5, math.pi); + cr.arc(x + self._radius, y + self._radius, self._radius, + math.pi, math.pi * 1.5); + + color = self._string_to_rgb(self._color.get_fill_color()) + cr.set_source_rgb(*color) + cr.fill_preserve(); + + color = self._string_to_rgb(self._color.get_stroke_color()) + cr.set_source_rgb(*color) + cr.set_line_width(line_width) + cr.stroke(); diff --git a/services/nm/nmclient.py b/services/nm/nmclient.py index 8097d57..fcc5638 100644 --- a/services/nm/nmclient.py +++ b/services/nm/nmclient.py @@ -22,9 +22,15 @@ import dbus.decorators import gobject import gtk import logging -from sugar.graphics.menu import Menu -from gettext import gettext as _ import os +from gettext import gettext as _ + +import hippo +from sugar.graphics.menu import Menu +from sugar.graphics import style +from sugar.graphics.iconcolor import IconColor +from sugar.graphics.timeline import Timeline +from bubble import Bubble import nminfo @@ -106,18 +112,13 @@ class Network(gobject.GObject): return self._valid def add_to_menu(self, menu): - item = gtk.CheckMenuItem() strength = self._strength if strength > 100: strength = 100 elif strength < 0: strength = 0 - label_str = "%s (%d%%)" % (self._ssid, strength) - label = gtk.Label(label_str) - label.set_alignment(0.0, 0.5) - item.add(label) - item.show_all() - menu.add(item) + item = NetworkMenuItem(text=self._ssid, percent=strength) + menu.add_item(item) class Device(gobject.GObject): @@ -188,14 +189,8 @@ class Device(gobject.GObject): del self._networks[net_op] def _add_to_menu_wired(self, menu): - item = gtk.CheckMenuItem() - label = gtk.Label(_("Wired Network")) - label.set_alignment(0.0, 0.5); - item.add(label) - if self._caps & NM_DEVICE_CAP_CARRIER_DETECT: - item.set_sensitive(self._link) - item.show_all() - menu.add(item) + item = NetworkMenuItem(_("Wired Network")) + menu.add_item(item) def _add_to_menu_wireless(self, menu): for net in self._networks.values(): @@ -270,22 +265,42 @@ class Device(gobject.GObject): def set_carrier(self, on): self._link = on -class ActivityMenu(Menu): - def __init__(self, activity_host): - Menu.__init__(self, activity_host.get_title()) - if not activity_host.get_shared(): - self._add_mesh_action() +class NetworkMenuItem(Bubble): + def __init__(self, text, percent=0): + color = IconColor("#646464,#646464") + Bubble.__init__(self, color=color, percent=percent) + + text_item = hippo.CanvasText(text=text) + style.apply_stylesheet(text_item, 'menu.Text') + self.append(text_item) + + +class NetworkMenu(gtk.Window): + __gsignals__ = { + 'action': (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, ([int])), + } + + def __init__(self): + gtk.Window.__init__(self, gtk.WINDOW_POPUP) + + canvas = hippo.Canvas() + self.add(canvas) + canvas.show() + + self._root = hippo.CanvasBox() + style.apply_stylesheet(self._root, 'menu') + canvas.set_root(self._root) - self._add_close_action() + def add_separator(self): + separator = hippo.CanvasBox() + style.apply_stylesheet(separator, 'menu.Separator') + self._root.append(separator) - def _add_mesh_action(self): - icon = CanvasIcon(icon_name='stock-share-mesh') - self.add_action(icon, ActivityMenu.ACTION_SHARE) + def add_item(self, item): + self._root.append(item) - def _add_close_action(self): - icon = CanvasIcon(icon_name='stock-close') - self.add_action(icon, ActivityMenu.ACTION_CLOSE) NM_STATE_UNKNOWN = 0 @@ -304,7 +319,6 @@ ICON_WIRELESS_81_100 = "stock-net-wireless-81-100" class NMClientApp: def __init__(self): - self.menu = None self.nminfo = None self._nm_present = False self._nm_state = NM_STATE_UNKNOWN @@ -313,6 +327,13 @@ class NMClientApp: self._active_device = None self._devices = {} + self._menu = None + self._hover_menu = False + self._timeline = Timeline(self) + self._timeline.add_tag('popup', 6, 6) + self._timeline.add_tag('before_popdown', 7, 7) + self._timeline.add_tag('popdown', 8, 8) + self._icons = {} self._cur_icon = None @@ -400,24 +421,61 @@ class NMClientApp: def _setup_trayicon(self): pixbuf = self._get_icon() self._trayicon = gtk.status_icon_new_from_pixbuf(pixbuf) - self._trayicon.connect("popup_menu", self._popup) - self._trayicon.connect("activate", self._popup) + self._trayicon.connect("popup_menu", self._status_icon_clicked) + self._trayicon.connect("activate", self._status_icon_clicked) self._schedule_icon_update() - def _popup(self, status, button=0, time=None): - def menu_pos(menu): - return gtk.status_icon_position_menu(menu, self._trayicon) + def _status_icon_clicked(self, button=0, time=None): + self._timeline.play(None, 'popup') + + def _get_menu_position(self, menu, item): + (screen, rect, orientation) = item.get_geometry() + [item_x, item_y, item_w, item_h] = rect + [menu_w, menu_h] = menu.size_request() + + x = item_x + item_w - menu_w + y = item_y + item_h + + x = min(x, screen.get_width() - menu_w) + x = max(0, x) - if time is None: - time = gtk.get_current_event_time() - if self.menu: - del self.menu - self.menu = self._construct_new_menu() - self.menu.popup(None, None, menu_pos, button, time) - self.menu.show_all() + y = min(y, screen.get_height() - menu_h) + y = max(0, y) + + return (x, y) + + def do_popup(self, current, n_frames): + if self._menu: + self._popdown() + return - def _construct_new_menu(self): - menu = gtk.Menu() + self._menu = self._create_menu() + self._menu.connect('enter-notify-event', + self._menu_enter_notify_event_cb) + self._menu.connect('leave-notify-event', + self._menu_leave_notify_event_cb) + (x, y) = self._get_menu_position(self._menu, self._trayicon) + self._menu.move(x, y) + self._menu.show_all() + + def do_popdown(self, current, frame): + if self._menu: + self._menu.destroy() + self._menu = None + + def _popdown(self): + self._timeline.play('popdown', 'popdown') + + def _menu_enter_notify_event_cb(self, widget, event): + self._hover_menu = True + self._timeline.play('popup', 'popup') + + def _menu_leave_notify_event_cb(self, widget, event): + self._hover_menu = False + self._popdown() + + def _create_menu(self): + menu = NetworkMenu() # Wired devices first for dev in self._devices.values(): @@ -427,6 +485,8 @@ class NMClientApp: continue dev.add_to_menu(menu) + menu.add_separator() + # Wireless devices second for dev in self._devices.values(): if not dev.is_valid(): -- cgit v0.9.1