Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian <icarito@sugarlabs.org>2011-04-13 00:54:55 (GMT)
committer Sebastian <icarito@sugarlabs.org>2011-04-13 00:54:55 (GMT)
commiteb6bc090d76a0acb87df7aea6292c3e2a14cc719 (patch)
tree6ed6426114d1b5937c8fb79944aebea4d06648d7
parent1666527af2e8109f4cab35b3e0d3607f8cfcc58b (diff)
Added generic About dialog.HEADmaster
-rw-r--r--ABOUT1
-rw-r--r--about.py314
-rw-r--r--activity.py5
-rw-r--r--icons/activity-about.svg100
4 files changed, 420 insertions, 0 deletions
diff --git a/ABOUT b/ABOUT
new file mode 100644
index 0000000..6255587
--- /dev/null
+++ b/ABOUT
@@ -0,0 +1 @@
+The "Hello world" Activity will print out "Hello world" on the screen. It is one of the simplest Activities possible in Sugar. Therefore, it can be used as a starting point to examine the activity code and create your own Sugar activity.
diff --git a/about.py b/about.py
new file mode 100644
index 0000000..6dd47a8
--- /dev/null
+++ b/about.py
@@ -0,0 +1,314 @@
+from gettext import gettext as _
+import gtk
+import gobject
+from sugar.graphics.toolbutton import ToolButton
+from sugar.graphics import style
+from sugar.graphics.icon import Icon
+from sugar.bundle.activitybundle import ActivityBundle
+from sugar.activity.activity import get_bundle_path
+from sugar.graphics.toolbutton import ToolButton
+from sugar.graphics.toolcombobox import ToolComboBox
+from sugar.graphics.combobox import ComboBox
+import os
+
+def get_info():
+ return { 10: { 'title':_('About this activity'),
+ 'widget':AboutThis},
+ 20: { 'title':_('How to contribute'),
+ 'widget':AboutHacking},
+ 30: { 'title':_('License'),
+ 'widget':AboutLicense},
+ 40: { 'title':_('Credits'),
+ 'widget':AboutCredits},
+ }
+
+class AboutPanel(gtk.EventBox):
+ exists = False
+ def __init__(self, *args, **kwargs):
+ super(AboutPanel, self).__init__(*args, **kwargs)
+
+ self.scrollwindow = gtk.ScrolledWindow()
+ self.scrollwindow.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ self.add(self.scrollwindow)
+ self.scrollwindow.show()
+
+ self.content_vbox = gtk.VBox()
+ self.viewport = gtk.Viewport()
+ self.viewport.add(self.content_vbox)
+ self.viewport.modify_bg(gtk.STATE_NORMAL, style.COLOR_WHITE.get_gdk_color())
+ self.scrollwindow.add(self.viewport)
+ self.show_all()
+
+ def add_section_from_file(self, filename, title=None):
+ text = None
+ filename = os.path.join(get_bundle_path(), filename)
+ lang = os.environ['LANG']
+ if lang.endswith("UTF-8"):
+ lang = lang[:-6]
+
+ try_file = filename + "." + lang
+ if os.path.isfile(try_file):
+ filename = try_file
+ else:
+ try_file = filename + "." + lang.split("_")[0]
+ if os.path.isfile(try_file):
+ filename = try_file
+
+ try:
+ fd = open(filename)
+ # remove 0x0c page breaks which can't be rendered in text views
+ text = fd.read().replace('\x0c', '')
+ fd.close()
+ except IOError:
+ return False
+
+ if text:
+ self.add_section(text, title)
+ return True
+
+ def add_section(self, text, title=None):
+ if title:
+ vbox = gtk.VBox()
+ separator = gtk.HSeparator()
+ vbox.pack_start(separator, expand=False)
+ separator.show()
+
+ label= gtk.Label(title)
+ label.set_alignment(0, 0)
+ vbox.pack_start(label, expand=False)
+ label.show()
+ self.content_vbox.pack_start(vbox, expand=False)
+
+ vbox = gtk.VBox()
+ vbox.set_border_width(style.DEFAULT_SPACING * 2)
+
+ # This is a workaround in sweets
+ #view = gtk.Label(text)
+ #view.set_line_wrap(True)
+ #view.set_alignment(0, 0)
+
+ # FIXME: This is the prefered method, scrolling goes crazy in sweets
+ view = gtk.TextView()
+ view.unset_flags(gtk.CAN_FOCUS)
+ view.set_cursor_visible(False)
+ view.set_editable(False)
+ view.get_buffer().set_text(text)
+ view.set_wrap_mode(gtk.WRAP_WORD)
+
+ vbox.pack_start(view)
+ self.content_vbox.pack_start(vbox, expand=False, fill=False)
+ view.show()
+
+class AboutThis(AboutPanel):
+ def __init__(self, *args, **kwargs):
+ super(AboutThis, self).__init__(*args, **kwargs)
+ bundle_name = ActivityBundle(get_bundle_path()).get_bundle_name()
+ title = _("About %s Activity" % bundle_name)
+ self.exists += self.add_section_from_file("ABOUT", title)
+ title = _('News')
+ self.exists += self.add_section_from_file("NEWS", title)
+ title = _('Read me')
+ self.exists += self.add_section_from_file("README", title)
+ if not self.exists:
+ self.add_section(_("There is currently no ABOUT file for this activity."), title)
+
+class AboutLicense(AboutPanel):
+ def __init__(self, *args, **kwargs):
+ super(AboutLicense, self).__init__(*args, **kwargs)
+ title = _("Know your rights")
+ self.exists += self.add_section_from_file("COPYING", title)
+
+class AboutCredits(AboutPanel):
+ def __init__(self, *args, **kwargs):
+ super(AboutCredits, self).__init__(*args, **kwargs)
+ title = _("Authors")
+ self.exists += self.add_section_from_file("AUTHORS", title)
+ title = _("Mantainers")
+ self.exists += self.add_section_from_file("MANTAINERS", title)
+
+class AboutHacking(AboutPanel):
+ def __init__(self, *args, **kwargs):
+ super(AboutHacking, self).__init__(*args, **kwargs)
+ title = _("Contributing code")
+ self.exists += self.add_section_from_file("HACKING", title)
+ self.exists += self.add_section_from_file("DEVELOPING", title)
+ title = _("Pending development tasks")
+ self.exists += self.add_section_from_file("TODO", title)
+
+class AboutButton(ToolButton):
+ def __init__(self, activity, **kwargs):
+ ToolButton.__init__(self, 'activity-about', **kwargs)
+ self.props.tooltip = _('About this activity')
+ self.props.accelerator = '<Ctrl>H'
+ self.connect('clicked', self.__about_button_clicked_cb, activity)
+
+ def __about_button_clicked_cb(self, button, activity):
+ about_dialog = _AboutDialog()
+ about_dialog.set_transient_for(self.get_toplevel())
+ about_dialog.show_all()
+
+class _AboutDialog(gtk.Window):
+ def __init__(self):
+ super(_AboutDialog, self).__init__()
+
+ offset = style.GRID_CELL_SIZE
+ width = gtk.gdk.screen_width() - offset * 2
+ height = gtk.gdk.screen_height() - offset * 2
+ self.set_size_request(width, height)
+ self.set_border_width(style.LINE_WIDTH)
+
+ self.modify_bg(gtk.STATE_NORMAL, style.COLOR_WHITE.get_gdk_color())
+ vbox = gtk.VBox()
+ self.add(vbox)
+ vbox.show()
+
+ self.set_position(gtk.WIN_POS_CENTER_ALWAYS)
+ self.set_decorated(False)
+ self.set_resizable(False)
+ self.set_modal(True)
+
+ self.toolbar = _DialogToolbar()
+ self.toolbar.connect('stop-clicked', self._stop_clicked_cb)
+ self.toolbar.connect('infopanel-changed', self._info_changed_cb)
+ vbox.pack_start(self.toolbar, False)
+
+ bundle = ActivityBundle(get_bundle_path())
+ icon = Icon(pixel_size=style.XLARGE_ICON_SIZE*2, file=bundle.get_icon())
+ icon_button = gtk.Button()
+ icon_button.set_image(icon)
+ icon_button.unset_flags(gtk.CAN_FOCUS)
+
+ container = gtk.VButtonBox()
+ container.add(icon_button)
+ container.set_layout(gtk.BUTTONBOX_START)
+
+ hbox = gtk.HBox()
+ hbox.set_border_width(style.DEFAULT_SPACING * 2)
+ hbox.set_spacing(style.DEFAULT_SPACING)
+ hbox.pack_start(container, expand=False, fill=False)
+ vbox.pack_start(hbox, expand=True, fill=True)
+
+ self.content_vbox = gtk.VBox()
+ self.content_vbox.set_border_width(style.DEFAULT_SPACING)
+ hbox.pack_start(self.content_vbox, expand=True, fill=True)
+
+ self._notebook = gtk.Notebook()
+ self._notebook.set_show_tabs(False)
+
+ self.panel = get_info()
+ for key in sorted(self.panel.keys()):
+ if self.panel[key]['widget']:
+ page = self.panel[key]['widget']()
+ if page.exists:
+ self._notebook.append_page(page)
+ self.toolbar.info_combo.append_item(key, self.panel[key]['title'])
+ self.toolbar.panel[key]=self.panel[key]
+ self.content_vbox.pack_start(self._notebook)
+ self.toolbar.info_combo.set_active(0)
+
+ self.connect('realize', self._realize_cb)
+
+ def _stop_clicked_cb(self, source):
+ self.destroy()
+
+ def _info_changed_cb(self, source):
+ active = self.toolbar.info_combo.get_active()
+ self._notebook.set_current_page(active)
+
+ def _realize_cb(self, source):
+ self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
+ self.window.set_accept_focus(True)
+
+class _DialogToolbar(gtk.Toolbar):
+ panel = {}
+ __gsignals__ = {
+ 'stop-clicked' : (gobject.SIGNAL_RUN_LAST, None, ()),
+ 'infopanel-changed': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([])),
+ }
+ def __init__(self):
+ super(_DialogToolbar, self).__init__()
+
+ self._add_separator()
+ icon_button = Icon(pixel_size=style.STANDARD_ICON_SIZE,
+ icon_name='activity-about')
+ #icon_button.connect('clicked', self._icon_button_clicked_cb)
+ self._add_widget(icon_button)
+ icon_button.unset_flags(gtk.CAN_FOCUS)
+
+ self._add_separator()
+ self.info_combo = ComboBox()
+ self.info_combo.props.sensitive = True
+ self._info_changed_cb_id = self.info_combo.connect('changed',
+ self._info_changed_cb)
+ combotool = ToolComboBox(self.info_combo)
+ self.insert(combotool, -1)
+ combotool.show()
+
+ #self.panel = get_info()
+ #for key in sorted(self.panel.keys()):
+ # self.info_combo.append_item(key, self.panel[key]['title'])
+ #self.info_combo.set_active(0)
+
+ self._back = ToolButton('go-previous-paired')
+ self._back.props.sensitive = False
+ self._back.connect('clicked', self.__go_back_cb)
+ self.insert(self._back, -1)
+ self._back.show()
+
+ self._forward = ToolButton('go-next-paired')
+ #self._forward.props.sensitive = False
+ self._forward.connect('clicked', self.__go_forward_cb)
+ self.insert(self._forward, -1)
+ self._forward.show()
+
+ self._add_separator(expand=True)
+
+ stop = ToolButton(icon_name='dialog-cancel')
+ stop.set_tooltip(_('Done'))
+ stop.connect('clicked', self._stop_clicked_cb)
+ self.add(stop)
+
+ def __go_back_cb(self, widget):
+ active = max(0, self.info_combo.get_active() - 1)
+ self.info_combo.set_active(active)
+ self._info_changed_cb(widget)
+ self.__set_nav_buttons(active)
+
+ def __go_forward_cb(self, widget):
+ active = min(len(self.panel.keys())-1, self.info_combo.get_active() + 1)
+ self.info_combo.set_active(active)
+ self._info_changed_cb(widget)
+ self.__set_nav_buttons(active)
+
+ def __set_nav_buttons(self,active):
+ if active==0:
+ self._back.props.sensitive = False
+ else:
+ self._back.props.sensitive = True
+
+ if active==len(self.panel.keys())-1:
+ self._forward.props.sensitive = False
+ else:
+ self._forward.props.sensitive = True
+
+ def _info_changed_cb(self, widget):
+ self.__set_nav_buttons(widget.get_active())
+ self.emit('infopanel-changed')
+
+ def _add_separator(self, expand=False):
+ separator = gtk.SeparatorToolItem()
+ separator.set_expand(expand)
+ separator.set_draw(False)
+ self.add(separator)
+
+ def _add_widget(self, widget):
+ tool_item = gtk.ToolItem()
+ tool_item.add(widget)
+ self.add(tool_item)
+
+ def _stop_clicked_cb(self, button):
+ self.emit('stop-clicked')
+
+
diff --git a/activity.py b/activity.py
index 5b06254..fe3da0b 100644
--- a/activity.py
+++ b/activity.py
@@ -29,6 +29,7 @@ from sugar.activity.widgets import TitleEntry
from sugar.activity.widgets import StopButton
from sugar.activity.widgets import ShareButton
from sugar.activity.widgets import KeepButton
+from about import AboutButton
class HelloWorldActivity(activity.Activity):
"""HelloWorldActivity class as specified in activity.info"""
@@ -66,6 +67,10 @@ class HelloWorldActivity(activity.Activity):
toolbar_box.toolbar.insert(separator, -1)
separator.show()
+ about_button = AboutButton(self)
+ toolbar_box.toolbar.insert(about_button, -1)
+ about_button.show()
+
stop_button = StopButton(self)
toolbar_box.toolbar.insert(stop_button, -1)
stop_button.show()
diff --git a/icons/activity-about.svg b/icons/activity-about.svg
new file mode 100644
index 0000000..2d2c139
--- /dev/null
+++ b/icons/activity-about.svg
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ height="55px"
+ viewBox="0 0 55 55"
+ width="55px"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.47 r22583"
+ sodipodi:docname="activity-about.svg">
+ <metadata
+ id="metadata14">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs12">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 27.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="55 : 27.5 : 1"
+ inkscape:persp3d-origin="27.5 : 18.333333 : 1"
+ id="perspective16" />
+ <inkscape:perspective
+ id="perspective2956"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ </defs>
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1024"
+ inkscape:window-height="548"
+ id="namedview10"
+ showgrid="true"
+ inkscape:zoom="5.8969072"
+ inkscape:cx="27.5"
+ inkscape:cy="30.043706"
+ inkscape:window-x="0"
+ inkscape:window-y="28"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg2"
+ showguides="false">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2818" />
+ </sodipodi:namedview>
+ <g
+ transform="translate(0,-0.125)"
+ id="g2920"
+ style="fill:none;stroke:#ffffff;stroke-opacity:1">
+ <path
+ style="fill:none;stroke:#ffffff;stroke-width:3.50000000000000000;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 50,27.625 c 0,12.3431 -10.1569,22.5 -22.5,22.5 C 15.1569,50.125 5,39.9681 5,27.625 5,15.2819 15.1569,5.125 27.5,5.125 c 12.3431,0 22.5,10.1569 22.5,22.5 z"
+ id="path2922" />
+ </g>
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:#ff0000;font-family:Bitstream Vera Sans"
+ x="70.381355"
+ y="23.771187"
+ id="text2822"><tspan
+ sodipodi:role="line"
+ id="tspan2824"
+ x="70.381355"
+ y="23.771187" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#ffffff;font-family:Century Schoolbook L;-inkscape-font-specification:Century Schoolbook L Bold"
+ x="20.459162"
+ y="42.070423"
+ id="text2826"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2828"
+ x="20.459162"
+ y="42.070423">i</tspan></text>
+</svg>