From eb6bc090d76a0acb87df7aea6292c3e2a14cc719 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Wed, 13 Apr 2011 00:54:55 +0000 Subject: Added generic About dialog. --- 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 = '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 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + i + -- cgit v0.9.1