From e1a599bb8508e1a0607e052a2f086289844dee60 Mon Sep 17 00:00:00 2001 From: Daniel Francis Date: Tue, 02 Oct 2012 01:20:34 +0000 Subject: Initial commit --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9f68a4d --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*~ +*.pyc +sudoku.desktop +sudoku.png diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..04eca7b --- /dev/null +++ b/Makefile @@ -0,0 +1,19 @@ +N=`python -c "import info; print info.lower_name"` +M=`python -c "import info; print info.file_filter_mime.replace('/', '-')"` +P=`python -c "import info; print info.file_filter_patterns"` +activity.info: + python makescripts/activity_luncher.py +activity: activity.info mimetypes.xml + cp activity.info activity/ + if [ -f mimetypes.xml ]; then cp mimetypes.xml activity; fi +app-entry.desktop: app-icon + python makescripts/desktop_luncher.py +install: app-entry.desktop mimetypes.xml + python makescripts/systeminstall.py + mv app-entry.desktop $N.desktop + xdg-desktop-menu install $N.desktop + if [ -f mimetypes.xml ]; then cp mimetypes.xml $M.xml; xdg-mime install $M.xml; python makescripts/svg2png.py activity/$M.svg ./mimetype.png; xdg-icon-resource install --context mimetypes --size 48 mimetype.png $M; fi +app-icon: + python makescripts/svg2png.py data/appicon.svg $N.png +mimetypes.xml: + if [ "$P" = "[]" ]; then echo "No mime types"; else python makescripts/mime_type.py; fi diff --git a/activity.info b/activity.info new file mode 100644 index 0000000..475641f --- /dev/null +++ b/activity.info @@ -0,0 +1,9 @@ +[Activity] +name = Sudoku +activity_version = 1 +show_launcher = 1 +bundle_id = org.gnome.Sudoku +exec = sugar-activity activity.Activity -s +icon = activity-sudoku +license = GPLv3 + diff --git a/activity.py b/activity.py new file mode 100644 index 0000000..c868c66 --- /dev/null +++ b/activity.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012 S. Daniel Francis +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +import tempfile +import os +os.environ['PROGRAMRUNNING'] = 'SUGAR' +import logging +logging.basicConfig(level=logging.DEBUG) +logger = logging.getLogger('graph-plotter') +from gettext import gettext as _ + +import gtk + +from sugar.datastore import datastore +from sugar.activity import activity + +try: + import sweetener +except ImportError: + import sys + sys.path.append(os.path.abspath('./sugar')) + import sweetener + +os.environ['DATA_DIR'] = os.path.abspath('./data') + +from options import Options +from canvas import Canvas + + +class Activity(activity.Activity): + def __init__(self, handle): + activity.Activity.__init__(self, handle) + self.options = Options(self) + self.options.show() + self.set_toolbar_box(self.options) + self.canvas = Canvas(self.options, self) + self.canvas.show() + self.set_canvas(self.canvas) + + def export(self, widget, data): + jobject = datastore.create() + jobject.metadata['title'] = self.metadata['title'] + mime_type = data[1] + jobject.metadata['mime_type'] = mime_type + file_path = tempfile.mktemp() + self.canvas.exports[mime_type](file_path) + jobject.set_file_path(file_path) + datastore.write(jobject) + + def read_file(self, path): + return self.canvas.read_file(path) + + def write_file(self, path): + return self.canvas.write_file(path) diff --git a/activity/activity-sudoku.sugar.svg b/activity/activity-sudoku.sugar.svg new file mode 100644 index 0000000..066871c --- /dev/null +++ b/activity/activity-sudoku.sugar.svg @@ -0,0 +1,29 @@ + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/activity/activity-sudoku.svg b/activity/activity-sudoku.svg new file mode 100644 index 0000000..640ea6d --- /dev/null +++ b/activity/activity-sudoku.svg @@ -0,0 +1,29 @@ + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/activity/activity.info b/activity/activity.info new file mode 100644 index 0000000..475641f --- /dev/null +++ b/activity/activity.info @@ -0,0 +1,9 @@ +[Activity] +name = Sudoku +activity_version = 1 +show_launcher = 1 +bundle_id = org.gnome.Sudoku +exec = sugar-activity activity.Activity -s +icon = activity-sudoku +license = GPLv3 + diff --git a/application.py b/application.py new file mode 100755 index 0000000..fe11039 --- /dev/null +++ b/application.py @@ -0,0 +1,267 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012 S. Daniel Francis +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +import os +import logging +logging.basicConfig(level=logging.DEBUG) +import glib +import info +logger = logging.getLogger(info.lower_name) +appname = info.name +# Some desktops like Gnome3-Shell show the Glib Prgname +glib.set_prgname(appname) +glib.set_application_name(appname) + +import gtk +from options import Options +from canvas import Canvas + +this_dir = os.path.split('__file__')[:-1] +if len(this_dir) == 1 and this_dir[0] == '': + this_dir = os.path.abspath('./') +else: + this_dir = os.path.join(this_dir) +os.chdir(this_dir) + +from gettext import gettext as _ + +if 'programabspath' in os.environ['DATADIR']: + datadir = os.environ['DATADIR'].replace('programabspath', + this_dir) +else: + datadir = os.environ['DATADIR'] + +if os.environ['ICONDIR'] != 'SYSTEM': + logger.debug(this_dir) + icondir = os.environ['ICONDIR'].replace('programabspath', + this_dir) + icon_theme = gtk.icon_theme_get_for_screen(gtk.gdk.screen_get_default()) + icon_theme.append_search_path(icondir) + + +class UnfullscreenButton(gtk.Window): + + def __init__(self): + gtk.Window.__init__(self) + + self.set_decorated(False) + self.set_resizable(False) + self.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG) + + self.set_border_width(0) + + self.props.accept_focus = False + + #Setup estimate of width, height + w, h = gtk.icon_size_lookup(gtk.ICON_SIZE_LARGE_TOOLBAR) + self._width = w + self._height = h + + self.connect('size-request', self._size_request_cb) + + screen = self.get_screen() + screen.connect('size-changed', self._screen_size_changed_cb) + + self._button = gtk.Button(stock=gtk.STOCK_LEAVE_FULLSCREEN) + self._button.set_relief(gtk.RELIEF_NONE) + self._button.show() + self.add(self._button) + + def connect_button_press(self, cb): + self._button.connect('button-press-event', cb) + + def _reposition(self): + x = gtk.gdk.screen_width() - self._width + self.move(x, 0) + + def _size_request_cb(self, widget, req): + self._width = req.width + self._height = req.height + self._reposition() + + def _screen_size_changed_cb(self, screen): + self._reposition() + + +class Application(gtk.Window): + def __init__(self): + gtk.Window.__init__(self) + self.save_type = info.io_mode + self.started = False + self.file_path = None + if info.file_filter_name: + self.filter = gtk.FileFilter() + self.filter.set_name(info.file_filter_name) + if info.file_filter_mime: + self.filter.add_mime_type(info.file_filter_mime) + for i in info.file_filter_patterns: + self.filter.add_pattern(i) + self.accel_group = gtk.AccelGroup() + self.add_accel_group(self.accel_group) + self.set_title(appname) + logger.debug(info.lower_name) + self.set_icon(gtk.gdk.pixbuf_new_from_file(os.path.join(datadir, + 'appicon.svg'))) + self.connect('delete-event', lambda w, e: self.stop()) + self.maximize() + self._vbox = gtk.VBox() + self.options = Options(self) + self.options.show() + self._vbox.pack_start(self.options, False, True, 0) + self.canvas = Canvas(self.options, self) + self.canvas.show() + self._vbox.pack_start(self.canvas, True, True, 0) + self.add(self._vbox) + self._vbox.show() + + self._is_fullscreen = False + self.set_events(gtk.gdk.ALL_EVENTS_MASK) + self.connect('motion-notify-event', self.motion_cb) + self.canvas.connect('expose-event', self.expose_event) + + def expose_event(self, widget, event): + logger.debug('Exposing') + if not self.started: + if self.file_path != None: + self.canvas.read_file(self.file_path) + self.set_title(os.path.abspath('%s - %s' % (self.file_path, + appname))) + else: + self.new() + self.started = True + + def motion_cb(self, widget, event): + if self._is_fullscreen: + x, y, state = self.get_window().get_pointer() + width, height = self.get_size() + button_width, button_height = self._unfullscreen_button.get_size() + if x >= width - button_width or y <= button_height: + self._unfullscreen_button.show() + else: + self._unfullscreen_button.hide() + + def fullscreen(self): + self.options.hide() + self._is_fullscreen = True + self._unfullscreen_button = UnfullscreenButton() + self._unfullscreen_button.set_transient_for(self) + self._unfullscreen_button.connect_button_press( + lambda w, e: self.unfullscreen()) + self._unfullscreen_button.show() + gtk.Window.fullscreen(self) + + def unfullscreen(self): + self.options.show() + self._is_fullscreen = False + self._unfullscreen_button.destroy() + gtk.Window.unfullscreen(self) + + def export(self, widget, data): + format_name = data[3] + filter_mime = data[2] + mime_type = data[1] + filechooser = gtk.FileChooserDialog(_("Export..."), self, + gtk.FILE_CHOOSER_ACTION_SAVE, + (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, + gtk.STOCK_OK, gtk.RESPONSE_OK)) + file_filter = gtk.FileFilter() + file_filter.set_name(format_name) + file_filter.add_mime_type(filter_mime) + filechooser.add_filter(file_filter) + filechooser.set_do_overwrite_confirmation(True) + filechooser.run() + file_path = filechooser.get_filename() + filechooser.destroy() + self.canvas.exports[mime_type](file_path) + + def new(self): + self.file_path = None + self.canvas.new() + self.set_title(appname) + + def stop(self): + if info.io_mode == info.CONFIG: + self.file_path = os.path.join(os.environ['HOME'], '.' + info.lower_name) + self.save() + gtk.main_quit() + + def open(self): + filechooser = gtk.FileChooserDialog(_('Open...'), self, + gtk.FILE_CHOOSER_ACTION_OPEN, + (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, + gtk.STOCK_OPEN, gtk.RESPONSE_OK)) + filechooser.add_filter(self.filter) + response = filechooser.run() + self.file_path = filechooser.get_filename() + filechooser.destroy() + if response == gtk.RESPONSE_OK: + logger.debug('Read file %s' % self.file_path) + self.canvas.read_file(self.file_path) + self.set_title('%s - %s' % (self.file_path, appname)) + + def save(self): + if self.file_path == None: + self.save_as() + else: + logger.debug('Write file %s' % self.file_path) + self.canvas.write_file(self.file_path) + + def save_as(self): + filechooser = gtk.FileChooserDialog(_('Save...'), self, + gtk.FILE_CHOOSER_ACTION_SAVE, + (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, + gtk.STOCK_OK, gtk.RESPONSE_OK)) + filechooser.add_filter(self.filter) + filechooser.set_do_overwrite_confirmation(True) + response = filechooser.run() + self.file_path = filechooser.get_filename() + filechooser.destroy() + if response == gtk.RESPONSE_OK: + logger.debug('Save file as %s' % self.file_path) + self.canvas.write_file(self.file_path) + self.set_title('%s - %s' % (self.file_path, appname)) + + +if __name__ == '__main__': + logger.debug('Initializing Graph Plotter') + import sys + if info.io_mode == info.DOCUMENT: + if len(sys.argv) > 1: + logger.debug('Open from args %s' % sys.argv[1]) + if os.path.exists(sys.argv[1]): + file_path = sys.argv[1] + logger.debug('Found file') + else: + file_path = None + logger.error('Could not find file') + else: + file_path = None + logger.debug('Create new file') + else: + if os.path.exists(os.path.join(os.environ['HOME'], '.' + info.lower_name)): + file_path = os.path.join(os.environ['HOME'], '.' + info.lower_name) + else: + file_path = None + window = Application() + window.file_path = file_path + window.show() + gtk.main() + logger.debug('Closing Graph Plotter') + exit() diff --git a/canvas.py b/canvas.py new file mode 100644 index 0000000..34eb00e --- /dev/null +++ b/canvas.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright 2012 S. Daniel Francis +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +import logging +logger = logging.getLogger('canvas') +import gtk + + +class Canvas(gtk.AspectFrame): + def __init__(self, toolbar_box, activity): + gtk.AspectFrame.__init__(self) + self.activity = activity + + def write_file(self, path): + pass + + def read_file(self, path): + pass + + + def new(self): + pass diff --git a/data/appicon.svg b/data/appicon.svg new file mode 100644 index 0000000..b332a6d --- /dev/null +++ b/data/appicon.svg @@ -0,0 +1,3183 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + This icon follows the Tango visual guidelines. +http://tango.freedesktop.org/ + +The pencil is based on the pencil created by Lapo Calamandrei for the GNOME icon theme. + + + + GNOME Sudoku + + + + Stephen Brandt + + + + + + + + http://www.stephenbrandt.com/ + http://gnome-sudoku.sourceforge.net/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/desktop/sweetener/__init__.py b/desktop/sweetener/__init__.py new file mode 100644 index 0000000..22ff499 --- /dev/null +++ b/desktop/sweetener/__init__.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012 S. Daniel Francis +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. diff --git a/desktop/sweetener/basic_options.py b/desktop/sweetener/basic_options.py new file mode 100644 index 0000000..83636e1 --- /dev/null +++ b/desktop/sweetener/basic_options.py @@ -0,0 +1,71 @@ +""" +This module provides a "File" menu at desktops and an ActivityToolbar at Sugar. +See class BasicOptions. +""" +# Copyright (C) 2012 S. Daniel Francis +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +from gettext import gettext as _ +import gtk + +import stock +from item import Item +from itemgroup import ItemGroup + +DOCUMENT = 0 +CONFIG = 1 + + +class BasicOptions(ItemGroup): + """This class has the basic options for your program.""" + def __init__(self, activity, box, export_formats=None): + """Create and append the basic items to a ItemBox. + activity -- The activity used as argument at Canvas and Options. + box -- sweetener.itembox.ItemBox of the activity. + export_formats -- list of tuples or none. Each tuple should have: + ['generic_type', 'mime_type', 'mime_filter', 'filter_name'] + """ + ItemGroup.__init__(self, box, _('_File'), None) + + if activity.save_type != CONFIG: + new = Item(gtk.STOCK_NEW, True) + new.connect('activate', lambda w: activity.new()) + self.append_item(new) + _open = Item(gtk.STOCK_OPEN, True) + _open.connect('activate', lambda w: activity.open()) + self.append_item(_open) + self.append_separator() + save_option = Item(gtk.STOCK_SAVE, True) + save_option.connect('activate', lambda w: activity.save()) + self.append_item(save_option) + save_as_option = Item(gtk.STOCK_SAVE_AS) + save_as_option.connect('activate', lambda w: activity.save_as()) + self.append_item(save_as_option) + if export_formats != None: + if len(export_formats) == 1: + stock.register('sweetener-%s' % export_formats[0][1], + _('Export as %s') % export_formats[0][0], + None, export_formats[0][1].replace('/', + '-')) + export = Item('sweetener-%s' % export_formats[0][1]) + export.connect('activate', activity.export, + export_formats[0]) + self.append_item(export) + self.append_separator() + _quit = Item(gtk.STOCK_QUIT) + _quit.connect('activate', lambda w: activity.stop()) + self.append_item(_quit) diff --git a/desktop/sweetener/item.py b/desktop/sweetener/item.py new file mode 100644 index 0000000..1b5fc8e --- /dev/null +++ b/desktop/sweetener/item.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012 S. Daniel Francis +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +import logging +logger = logging.getLogger('option') + +import gobject +import gtk + +import stock + + +class Item(gobject.GObject): + __gsignals__ = {'activate': (gobject.SIGNAL_RUN_LAST, + gobject.TYPE_NONE, + tuple())} + menuitem = None + toolitem = None + + def __init__(self, stock_id=None, important=False): + gobject.GObject.__init__(self) + self._stock_id = stock_id + self.accel_group = None + self.important = important + self.connection = None + self.connection_data = None + self.tooltip = None + + def set_stock_id(self, stock_id): + self._stock_id = stock_id + + def get_stock_id(self): + return self._stock_id + + stock_id = property(get_stock_id, set_stock_id) + + def get_menu_item(self): + self.menuitem = gtk.ImageMenuItem(self._stock_id) + self.menuitem.connect('activate', self.activate_cb) + self.setup_accelerator() + return self.menuitem + + def activate_cb(self, widget): + self.emit('activate') + + def setup_accelerator(self): + accelerator = stock.get_accelerator(self.stock_id) + logger.debug(str(accelerator)) + if accelerator[1] > 0: + self.menuitem.add_accelerator('activate', + self.accel_group, accelerator[1], accelerator[0], + gtk.ACCEL_VISIBLE) + + def get_tool_item(self): + self.toolitem = gtk.ToolButton(self._stock_id) + self.toolitem.connect('clicked', self.activate_cb) + self.setup_tooltip() + return self.toolitem + + def setup_tooltip(self): + if self.tooltip: + self.toolitem.set_tooltip_text(self.tooltip) + else: + text = gtk.stock_lookup(self.stock_id)[1] + self.toolitem.set_tooltip_text(text.replace('_', '')) + + def emit_signal(self, widget, signal_name): + print self.stock_id + print self.get_stock_id() + self.emit(signal_name) diff --git a/desktop/sweetener/itembox.py b/desktop/sweetener/itembox.py new file mode 100644 index 0000000..b7ff60d --- /dev/null +++ b/desktop/sweetener/itembox.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012 S. Daniel Francis +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +import gtk + + +class ItemBox(gtk.VBox): + def __init__(self, activity): + gtk.VBox.__init__(self) + self._parent = activity + self.menubar = gtk.MenuBar() + self.toolbar = gtk.Toolbar() + self.pack_start(self.menubar, False, True, 0) + self.pack_start(self.toolbar, False, True, 0) + self.menubar.show() + self.toolbar.show() diff --git a/desktop/sweetener/itemgroup.py b/desktop/sweetener/itemgroup.py new file mode 100644 index 0000000..3e4780e --- /dev/null +++ b/desktop/sweetener/itemgroup.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012 S. Daniel Francis +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +import gobject +import gtk + + +class ItemGroup(gobject.GObject): + def __init__(self, box, name=None, icon=None): + gobject.GObject.__init__(self) + self.items = [] + self.first_important = True + self.item = gtk.MenuItem(name) + box.menubar.append(self.item) + self.menu = gtk.Menu() + self.item.set_submenu(self.menu) + self.menu.show() + self.item.show() + self.activity = box._parent + self.accel_group = box._parent.accel_group + self.toolbar = box.toolbar + + def append_item(self, item): + item.accel_group = self.accel_group + menuitem = item.get_menu_item() + menuitem.show() + self.menu.append(menuitem) + if item.important: + if self.first_important and len(self.toolbar): + separator = gtk.SeparatorToolItem() + separator.show() + self.toolbar.insert(separator, -1) + self.first_important = False + tool_item = item.get_tool_item() + self.toolbar.insert(tool_item, -1) + tool_item.show() + self.items.append(item) + + def append_separator(self, important=False): + menuitem = gtk.SeparatorMenuItem() + menuitem.show() + self.menu.append(menuitem) + if important: + toolitem = gtk.SeparatorToolItem() + toolitem.show() + self.toolbar.insert(toolitem, -1) + return toolitem + + +class GhostGroup(ItemGroup): + + def __init__(self, box, name): + ItemGroup.__init__(self, box, name) + + +class SubGroup(ItemGroup): + def __init__(self, group, name=None): + gobject.GObject.__init__(self) + self.items = [] + self.item = gtk.MenuItem(name) + group.menu.append(self.item) + self.menu = gtk.Menu() + self.item.set_submenu(self.menu) + self.menu.show() + self.item.show() + self.accel_group = group.accel_group + self.toolbar = group.toolbar + self.first_important = True diff --git a/desktop/sweetener/stock.py b/desktop/sweetener/stock.py new file mode 100644 index 0000000..4f3b213 --- /dev/null +++ b/desktop/sweetener/stock.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012 S. Daniel Francis +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +import logging +logger = logging.getLogger('stock') +import gtk + +icon_factory = gtk.IconFactory() + + +def register(name, label, accelerator, icon_name): + if accelerator == None: + keyval = 0 + mask = 0 + else: + keyval, mask = gtk.accelerator_parse(accelerator) + gtk.stock_add([(name, label, mask, keyval, '')]) + if icon_name: + icon_source = gtk.IconSource() + icon_source.set_icon_name(icon_name) + icon = gtk.IconSet() + icon.add_source(icon_source) + icon_factory.add(name, icon) + icon_factory.add_default() + + +def overwrite_stock(stock_id, new_accelerator): + info = list(gtk.stock_lookup(stock_id)) + keyval, mask = gtk.accelerator_parse(new_accelerator) + info[2] = mask + info[3] = keyval + logger.debug(str(info)) + gtk.stock_add([(info[0], info[1], info[2], info[3], info[4])]) + +# Here we overwrite the key accelerators for some stock ids. +# Feel free to add here any other stock id if you need it at your activity, +# and send us a patch. + +overwrite_stock(gtk.STOCK_SAVE_AS, 'S') +overwrite_stock(gtk.STOCK_ZOOM_IN, 'plus') +overwrite_stock(gtk.STOCK_ZOOM_OUT, 'minus') +overwrite_stock(gtk.STOCK_ZOOM_100, '0') +# Key accelerator will be F11 on desktops and return on Sugar. +overwrite_stock(gtk.STOCK_FULLSCREEN, 'F11') +overwrite_stock(gtk.STOCK_ADD, 'A') +overwrite_stock(gtk.STOCK_REMOVE, 'Delete') +overwrite_stock(gtk.STOCK_SELECT_COLOR, 'L') + + +def get_label(stock, underline): + text = gtk.stock_lookup(stock)[1] + if underline: + text = text.replace('_', '') + return text + + +def get_accelerator(stock): + return gtk.stock_lookup(stock)[2:-1] diff --git a/info.py b/info.py new file mode 100644 index 0000000..03410b3 --- /dev/null +++ b/info.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012 S. Daniel Francis +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +import logging +logger = logging.getLogger('info') + +from gettext import gettext as _ + +service_name = 'org.gnome.Sudoku' + +import os +this_dir = os.path.abspath('./') + +import gettext +if 'PROGRAMRUNNING' in os.environ: + if os.environ['PROGRAMRUNNING'] == 'DESKTOP': + # init gettext + locale_path = os.environ['TRANSLATIONDIR'].replace('programabspath', + this_dir) + logger.debug(locale_path) + gettext.bindtextdomain(service_name, locale_path) + gettext.textdomain(service_name) +_ = gettext.gettext + + +DOCUMENT = 0 +CONFIG = 1 +io_mode = CONFIG + +generic_name = _('Sudoku puzzle') +name = _('Sudoku') +lower_name = 'sudoku' +copyright = 'Copyright © 2012 Daniel Francis' +version = '1' +description = _('Logic-based combinatorial number-placement puzzle.') +authors = ['Daniel Francis '] +url = None +documentation = None +categories = ['GNOME', 'GTK', 'Game', 'LogicGame'] + +file_filter_name = None +file_filter_mime = None +file_filter_patterns = [] + +# Refer to the COPYING +license = 'GPLv3' +try: + license_file = open(os.path.join(os.environ['DATADIR'].replace( + 'programabspath', this_dir), 'COPYING')) + license_content = license_file.read() + license_file.close() +except: + license_content = None diff --git a/makesripts/activity_luncher.py b/makesripts/activity_luncher.py new file mode 100644 index 0000000..378cf84 --- /dev/null +++ b/makesripts/activity_luncher.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012 S. Daniel Francis +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +import ConfigParser +import sys +import os +appdir = os.path.abspath('./') +sys.path.append(appdir) + +import info + +activity_file_stream = open('activity.info', 'w') +activity_file = ConfigParser.RawConfigParser() +activity_file.add_section('Activity') +activity_file.set('Activity', 'name', info.name) +activity_file.set('Activity', 'activity_version', + info.version) +activity_file.set('Activity', 'show_launcher', '1') +activity_file.set('Activity', 'bundle_id', info.service_name) +activity_file.set('Activity', 'exec', + 'sugar-activity activity.Activity -s') +activity_file.set('Activity', 'icon', 'activity-' + info.lower_name) +activity_file.set('Activity', 'license', info.license) +if info.file_filter_mime: + activity_file.set('Activity', 'mime_types', info.file_filter_mime) +activity_file.write(activity_file_stream) +activity_file_stream.close() diff --git a/makesripts/svg2png.py b/makesripts/svg2png.py new file mode 100644 index 0000000..06eab59 --- /dev/null +++ b/makesripts/svg2png.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012 S. Daniel Francis +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +import sys +import os +appdir = os.path.abspath('./') +sys.path.append(appdir) +import gtk + +import info + +pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(sys.argv[1], 48, 48) +pixbuf.save(sys.argv[2], 'png') diff --git a/options.py b/options.py new file mode 100644 index 0000000..9e06358 --- /dev/null +++ b/options.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright 2012 S. Daniel Francis +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +from gettext import gettext as _ +import gobject +import gtk + +from sweetener.itembox import ItemBox +from sweetener.basic_options import BasicOptions + + +class Options(ItemBox): + def __init__(self, activity): + ItemBox.__init__(self, activity) + self.activity = activity + self.basic = BasicOptions(activity, self, + None) diff --git a/setup.py b/setup.py new file mode 100755 index 0000000..530f97c --- /dev/null +++ b/setup.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python + +# Copyright (C) 2006, Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +from sugar.activity import bundlebuilder + +bundlebuilder.start() diff --git a/sudoku b/sudoku new file mode 100755 index 0000000..aede908 --- /dev/null +++ b/sudoku @@ -0,0 +1,35 @@ +#!/usr/bin/env python +# +# Copyright 2012 Daniel Francis +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. +# + +import sys +import os +self_path = os.path.abspath(__file__) +print self_path +current_list_dir = os.path.split(self_path)[:-1][0] +print current_list_dir +os.chdir(current_list_dir) +sys.path.append(os.path.join(current_list_dir, 'desktop')) +os.environ['PYTHONPATH'] = ':'.join(sys.path) +os.environ['DATADIR'] = 'programabspath/data' +os.environ['TRANSLATIONDIR'] = 'programabspath/locale' +os.environ['PROGRAMRUNNING'] = 'DESKTOP' +os.environ['ICONDIR'] = 'programabspath/desktop/icons' +os.system('python application.py %s' % (('"%s"' % sys.argv[1]) + if len(sys.argv) > 1 else '')) diff --git a/sugar/sweetener/__init__.py b/sugar/sweetener/__init__.py new file mode 100644 index 0000000..22ff499 --- /dev/null +++ b/sugar/sweetener/__init__.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012 S. Daniel Francis +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. diff --git a/sugar/sweetener/basic_options.py b/sugar/sweetener/basic_options.py new file mode 100644 index 0000000..52f4ebd --- /dev/null +++ b/sugar/sweetener/basic_options.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012 S. Daniel Francis +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +from gettext import gettext as _ + +from sugar.activity.widgets import ActivityToolbarButton + +import stock +from item import Item + +DOCUMENT = 0 +CONFIG = 1 + + +class BasicOptions(ActivityToolbarButton): + def __init__(self, activity, box, export_formats=None): + ActivityToolbarButton.__init__(self, activity) + box.toolbar.insert(self, 0) + self.show() + if export_formats != None: + if len(export_formats) == 1: + stock.register('sweetener-%s' % export_formats[0][1], + _('Export as %s') % export_formats[0][0], + None, export_formats[0][1].replace('/', + '-')) + export = Item('sweetener-%s' % export_formats[0][1]) + export.connect('activate', activity.export, + export_formats[0]) + self.page.insert(export.get_tool_item(), -1) diff --git a/sugar/sweetener/item.py b/sugar/sweetener/item.py new file mode 100644 index 0000000..291204a --- /dev/null +++ b/sugar/sweetener/item.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012 S. Daniel Francis +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +import logging +logger = logging.getLogger('option') + +import gobject +import gtk +from sugar.graphics.toolbutton import ToolButton + +import stock + + +class Item(gobject.GObject): + __gsignals__ = {'activate': (gobject.SIGNAL_RUN_LAST, + gobject.TYPE_NONE, + tuple())} + toolitem = None + + def __init__(self, stock_id=gtk.STOCK_CLEAR, important=False): + gobject.GObject.__init__(self) + self._stock_id = stock_id + self.accel_group = None + self.important = important + self.connection = None + self.connection_data = None + self.tooltip = None + + def set_stock_id(self, stock_id): + self._stock_id = stock_id + + def get_stock_id(self): + return self._stock_id + + stock_id = property(get_stock_id, set_stock_id) + + def get_menu_item(self): + return None + + def activate_cb(self, widget): + self.emit('activate') + + def setup_accelerator(self): + accelerator = stock.get_accelerator(self._stock_id) + logger.debug(str(accelerator)) + try: + if accelerator[1] > 0: + self.toolitem.props.accelerator = gtk.accelerator_name( + accelerator[1], accelerator[0]) + except: + logger.error( +'Could not set up accelerator; if toogletoolbutton, update your sugar version') + + def get_tool_item(self): + if self._stock_id in stock.icons: + icon_name = stock.icons[self._stock_id] + else: + icon_name = self._stock_id + self.toolitem = ToolButton(icon_name) + self.toolitem.connect('clicked', self.activate_cb) + self.setup_tooltip() + return self.toolitem + + def setup_tooltip(self): + if self.tooltip: + self.toolitem.set_tooltip(self.tooltip) + else: + text = gtk.stock_lookup(self._stock_id)[1] + self.toolitem.set_tooltip(text.replace('_', '')) + self.setup_accelerator() diff --git a/sugar/sweetener/itembox.py b/sugar/sweetener/itembox.py new file mode 100644 index 0000000..d861c52 --- /dev/null +++ b/sugar/sweetener/itembox.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012 S. Daniel Francis +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +import gtk +from sugar.graphics.toolbarbox import ToolbarBox +from sugar.activity.widgets import StopButton + + +class ItemBox(ToolbarBox): + def __init__(self, activity): + ToolbarBox.__init__(self) + self._parent = activity + separator = gtk.SeparatorToolItem() + separator.set_draw(False) + separator.set_expand(True) + separator.show() + self.toolbar.insert(separator, -1) + self.stopbutton = StopButton(activity) + self.toolbar.insert(self.stopbutton, -1) + self.stopbutton.show() diff --git a/sugar/sweetener/stock.py b/sugar/sweetener/stock.py new file mode 100644 index 0000000..a6451a7 --- /dev/null +++ b/sugar/sweetener/stock.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012 S. Daniel Francis +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +import logging +logger = logging.getLogger('stock') +import gtk + +icon_factory = gtk.IconFactory() + +# Set the icon name for the stock items, this is used only in Sugar. +icons = {gtk.STOCK_ADD: 'list-add'} + + +def register(name, label, accelerator, icon_name): + if accelerator == None: + keyval = 0 + mask = 0 + else: + keyval, mask = gtk.accelerator_parse(accelerator) + gtk.stock_add([(name, label, mask, keyval, '')]) + if icon_name: + icon_source = gtk.IconSource() + icon_source.set_icon_name(icon_name) + icon = gtk.IconSet() + icon.add_source(icon_source) + icon_factory.add(name, icon) + icon_factory.add_default() + icons[name] = icon_name + + +def overwrite_stock(stock_id, new_accelerator): + info = list(gtk.stock_lookup(stock_id)) + keyval, mask = gtk.accelerator_parse(new_accelerator) + info[2] = mask + info[3] = keyval + logger.debug(str(info)) + gtk.stock_add([(info[0], info[1], info[2], info[3], info[4])]) + +# Here we overwrite the key accelerators for some stock ids. +# Feel free to add here any other stock id if you need it at your activity, +# and send us a patch. + +overwrite_stock(gtk.STOCK_ZOOM_IN, 'plus') +overwrite_stock(gtk.STOCK_ZOOM_OUT, 'minus') +overwrite_stock(gtk.STOCK_ZOOM_100, '0') +# Key accelerator will be F11 on desktops and return on Sugar. +overwrite_stock(gtk.STOCK_FULLSCREEN, 'Return') +overwrite_stock(gtk.STOCK_ADD, 'A') +overwrite_stock(gtk.STOCK_REMOVE, 'R') +overwrite_stock(gtk.STOCK_SELECT_COLOR, 'L') + + +def get_label(stock, underline): + text = gtk.stock_lookup(stock)[1] + if underline: + text = text.replace('_', '') + return text + + +def get_accelerator(stock): + return gtk.stock_lookup(stock)[2:-1] -- cgit v0.9.1