diff options
Diffstat (limited to 'writing-sugar-activities.tex')
-rw-r--r-- | writing-sugar-activities.tex | 1036 |
1 files changed, 1035 insertions, 1 deletions
diff --git a/writing-sugar-activities.tex b/writing-sugar-activities.tex index cc42513..59a214c 100644 --- a/writing-sugar-activities.tex +++ b/writing-sugar-activities.tex @@ -1,3 +1,1037 @@ \mode* % Reset \mode<all> from slides.tex -% TODO: This part is yet to be written. +\section{\en{Overview of Sugar and GTK+}\es{Visión general de Sugar y GTK+}} + +\en{The Sugar platform is what runs on the XO. Sugar itself is written in +Python, but uses a system called GTK+ as its underlying UI toolkit. GTK+ is a +popular UI toolkit, used by many projects on Linux (not just on the XO).} +\es{La plataforma de Sugar es lo que se ejecuta en la XO. Sugar sí está escrito +en Python, pero utiliza un sistema llamado GTK+ como su kit de herramientas de +interfaz de usuario (IU) subyacente. GTK+ es un popular juego de herramientas de +interfaz de usuario, que se utiliza por muchos proyectos en Linux (y no sólo en +la XO).} + +\en{Sugar's distinctive appearance is due to a theme it applies to the default +GTK+ widgets. Without this theme, activities on the XO would look very similar +to normal Linux programs (such as gedit).} +\es{El aspecto distintivo de Sugar es debido a un tema que se aplica a los +widgets GTK+ predeterminados. Sin este tema, las actividades en la XO se vería +muy similar a los programas normales de Linux (como gedit).} + +\en{As with Python, there are two major versions of GTK+ available at the +moment: GTK+~2 and GTK+~3. GTK+~3 is the recommended version, and is available +on the XO. All software should be written using GTK+~3 using GIR (GObject +Introspection) and \emph{not} PyGTK (which is out of date).} +\es{Al igual que con Python, hay dos versiones principales de GTK+ disponibles +en este momento: GTK+~2 y GTK+~3. GTK+~3 es la versión recomendada, y está +disponible en la XO. Todo el software debe ser escrito usando GTK+~3 y GIR +(introspección GObject) y \emph{no} PyGTK (que es obsoleta).} + +\en{Similarly, there are two versions of Sugar code available: \texttt{sugar} +and \texttt{sugar3}. \texttt{sugar} uses GTK+~2, whereas \texttt{sugar3} uses +GTK+~3. All new software should be written using \texttt{sugar3}.} +\es{Del mismo modo, hay dos versiones de código de Sugar disponibles: +\texttt{sugar} y \texttt{sugar3}. \texttt{sugar} usa GTK+~2, mientras que +\texttt{sugar3} usa GTK+~3. Todas las novedades software debe ser escrito con +\texttt{sugar3}.} + +\begin{frame}{\en{Sugar and GTK+}\es{Sugar y GTK+}} +\begin{itemize} + \item{\en{All XO activities use Sugar} + \es{Todas las actividades XO utilizan Sugar}} + \item{\en{Sugar is built on GTK+~3}\es{El Sugar se basa en GTK+~3}} + \item{\en{Use \texttt{sugar3} and GTK+~3} + \es{Debe utilizar \texttt{sugar3} y GTK+~3}} +\end{itemize} +\end{frame} + + +\section{\en{Introduction to GTK+}\es{Introducción a GTK+}} + +\en{GTK+ is based on the concept of a hierarchy of \emph{widgets}. A widget is +a single graphical control, such as a button, some text, a toolbar, or a +window. These widgets are built into a hierarchy, with child widgets inside +parent widgets. For example, when a button is shown next to an image, a menu bar +and a label in a window, this widget hierarchy is used:} +\es{GTK+ se basa en el concepto de una jerarquía de \emph{widgets}. Un widget es +un control gráfico único, tal como un botón, un texto, una barra de +herramientas, o una ventana. Estos widgets están integradas en una jerarquía, +con widgets hijos dentro de los widgets de los padres. Por ejemplo, cuando se +muestra un botón al lado de la imagen, una barra de menús y una etiqueta en una +ventana, se utiliza esta jerarquía de controles:} + +\begin{frame}{\en{GTK+ widget hierarchy}\es{Jerarquía de widgets de GTK+}} +\begin{itemize} + \item{\texttt{Gtk.Window}\begin{itemize} + \item{\texttt{Gtk.Box}\begin{itemize} + \item{\texttt{Gtk.MenuBar}} + \item{\texttt{Gtk.Label}} + \item{\texttt{Gtk.Image}} + \item{\texttt{Gtk.Button}} + \end{itemize}} + \end{itemize}} +\end{itemize} +\end{frame} + +\begin{frame}{\en{GTK+ widget hierarchy}\es{Jerarquía de widgets de GTK+}} +\begin{figure}[h!] + \centering + \includegraphics[width=0.4\textwidth]{example-ui.png} + \caption{\en{The example UI.} + \es{Un ejemplo de un IU.}} + \label{fig:example-ui} +\end{figure} +\end{frame} + +\en{Widgets are roughly divided between normal controls and layout containers +(such as \texttt{Gtk.Box} in the example hierarchy). Other code in GTK+ supports +key bindings, drag-and-drop and the clipboard.} +\es{Widgets están divididos más o menos entre los controles normales y +contenedores de diseño (como \texttt{Gtk.Box} en la jerarquía de ejemplo). Otro +código en GTK+ soporta atajos de teclado, arrastrar y soltar y el portapapeles.} + +\note{Give an interactive demo of Glade and \texttt{example-ui.ui} now.} + +\en{\emph{Glade} is a popular tool for building UIs with GTK+. It isn't +normally used when creating Sugar activities, but is useful for exploring the +widget hierarchy.} +\es{\emph{Glade} es una herramienta popular para la creación de IUs con GTK+. No +se suele utilizar cuando se crean actividades para Sugar, pero es útil para +explorar la jerarquía de widgets.} + + +\section{\en{Building an interactive UI}\es{Construcción de una IU interactiva}} + +\en{To build a UI in GTK+, construct a Python object for each widget, and then +call methods on the container widgets to add child widgets to parents and thus +construct a hierarchy.} +\es{Para construir una IU en GTK+, construir un objeto de Python para cada +widget, y luego llamar a métodos en los widgets de contenedores para añadir +hijos a los padres y así la construcción de una jerarquía.} + +\begin{frame}[fragile] +\frametitle{\en{Constructing a GTK+ widget hierarchy} + \es{Construcción de una jerarquía de widgets de GTK+}} +\begin{lstlisting}[language=Python,basicstyle={\ttfamily\footnotesize}] +from gi.repository import Gtk + +window = Gtk.Window(title='Hola Mundo') + +# Crear widget contenedor. +box = Gtk.Box() +box.set_orientation(Gtk.Orientation.VERTICAL) +window.add(box) +# Crear una etiqueta, una imagen y un boton. +label = Gtk.Label('Logo OLPC:') +box.add(label) +image = Gtk.Image() +image.set_from_file('olpc-square_logo.jpg') +box.add(image) +button = Gtk.Button() +button.set_label('Boton') +box.add(button) + +# Mostrar la IU. +window.show_all() +Gtk.main() +\end{lstlisting} +\end{frame} + + +\en{In this example, the last two lines of code require explanation. Every GTK+ +widget can be hidden, and all are hidden by default. Before they can be used by +the user they need to be shown --- either by calling the \texttt{show()} method +on each widget, or by calling the \texttt{show\_all()} method on one of the +container widgets which contains them (such as the top-level window, for +example).} +\es{En este ejemplo, las dos últimas líneas de código requieren de una +explicación. Cada widget de GTK+ se puede ocultar, y todos se oculta de manera +predeterminada. Antes de que puedan ser utilizados por el usuario, es necesario +que se muestra --- o bien llamando al método \texttt{show()} de cada widget, o +llamando al método \texttt{show\_all()} en uno de los widgets de contenedor que +los contiene (como la ventana de nivel superior, por ejemplo).} + +\en{The last line of code starts the GTK+ \emph{main loop}. This is what +handles user input and drawing of widgets in a UI. The main loop is an infinite +loop which:} +\es{La última línea de código se inicia el \emph{bucle principal} de GTK+. Esto +es lo que se encarga de la entrada del usuario y el dibujo de widgets en una IU. +El bucle principal es un bucle infinito que:} + +\begin{frame}{\en{GTK+ main loop}\es{Bucle principal de GTK+}} +\begin{enumerate} + \item{\en{Receives input events from the user (such as mouse movements or + keyboard button presses)} + \es{Recibe los eventos de entrada del usuario (por ejemplo, los + movimientos del ratón o pulsaciones de botones del teclado)}} + \item{\en{Calls \emph{event handlers} for those events} + \es{Llamadas \emph{controladores de eventos} para los eventos}} + \item{\en{Waits for the next input event, then loops} + \es{Espera a que el próximo evento de entrada, entonces se realiza un + bucle}} +\end{enumerate} +\end{frame} +% TODO: Diagram of the main loop? + +\en{This is a standard event-based programming model. It means that after +calling the \texttt{Gtk.main()} function, all code in your program is executed +inside callbacks from this main loop. A callback is where the main loop calls +a function provided by your code: the main loop \emph{calls back} to your +code.} +\es{Este es un modelo de programación estándar basado en eventos. Esto significa +que después de llamar a la función \texttt{Gtk.main()}, todo el código de su +programa se ejecuta dentro de callbacks de este bucle principal. Un callback es +donde el bucle principal llama a una función proporcionada por su código: el +bucle principal \emph{vuelve a llamar} a su código.} + + +\section{\en{Signal handling}\es{Manejo de señales}} + +\en{Almost all callbacks in GTK+ are for \emph{signals} from widgets. These +correspond to events on the widgets. For example, the \texttt{Button} widget +emits a \texttt{clicked} signal when the user clicks it. Zero or more callbacks +can be \emph{connected} for this signal, all of which will be called from the +main loop when the button is clicked.} +\es{Casi todas las callbacks en GTK+ son para señales de widgets. Estos +corresponden a eventos en los widgets. Por ejemplo, el widget \texttt{Button} +emite una señal de \texttt{clicked} cuando el usuario hace clic en él. Cero o +más callbacks se pueden conectar a esta señal, todos los cuales serán llamados +desde el bucle principal cuando se hace clic en el botón.} + +\en{A signal handler can be connected by calling the \texttt{connect()} method, +passing the name of the signal, and the name of the function to use as a +callback. This function must accept the parameters specified in the +documentation for the signal. It is common practice (though not required) to +suffix callback function names with \texttt{\_cb} (which stands for +`callback').} +\es{Un manejador de la señal se puede conectar mediante una llamada al método +\texttt{connect()}, pasando el nombre de la señal, y el nombre de la función +para utilizarla como un callback. Esta función debe aceptar los parámetros +especificados en la documentación de la señal. Es una práctica común (aunque no +es obligatorio) a los nombres de funciones callback con sufijo \texttt{\_cb} +(que significa `callback').} + +\en{In this example, we subclass \texttt{Gtk.Window} so that the signal callback +can be included as a private method of the window. This is a tidy way to do +things, as it prevents callbacks from different windows getting mixed up.} +\es{En este ejemplo, subclase \texttt{Gtk.Window} de modo que el callback de la +señal puede ser incluido como un método privado de la ventana. Esta es una +manera ordenada de hacer las cosas, ya que evita que callbacks de diferentes +ventanas se mezclen.} + +\begin{frame}[fragile] +\frametitle{\en{GTK+ signal handlers}\es{Manejadores de señales de GTK+}} +\begin{lstlisting}[language=Python,basicstyle={\ttfamily\footnotesize}] +# Subclase Window para crear una ventana. +class MyWindow(Gtk.Window): + def __init__(self): + super(MyWindow, self).__init__() + + # Crear y anadir un boton. + button = Gtk.Button('Hola Mundo') + button.show() + self.add(button) + + # Conecte un manejador de senales. + button.connect('clicked', + self.__button_clicked_cb) + + def __button_clicked_cb(self, button): + print('Boton se hizo clic!') + +window = MyWindow() +window.show() +Gtk.main() +\end{lstlisting} +\end{frame} + +\en{Signal handling is one of the key features of GTK+, and is worth +understanding.} +\es{Manipulación de las señales es una de las características principales de +GTK+, y vale la pena comprensión.} + +\begin{frame}{\en{Signal handling tutorials}\es{Tutoriales sobre el manejo de señales}} +\begin{itemize} + \item{\url{\en{https://developer.gnome.org/gnome-devel-demos/stable/signals-callbacks.py.html.en} + \es{https://developer.gnome.org/gnome-devel-demos/stable/signals-callbacks.py.html.es}}} + \item{\url{http://python-gtk-3-tutorial.readthedocs.org/en/latest/basics.html\#main-loop-and-signals}} +\end{itemize} +\end{frame} + + +\section{\en{GTK+ documentation}\es{Documentación de GTK+}} + +\en{GTK+ is a huge library, and covering it in detail here would take too long. +There are several good tutorials for using GTK+ in Python, available in several +languages. It is recommended that you read them and practice the exercises they +give. The \href{https://developer.gnome.org/gtk3/stable/ch03.html}{GTK+ widget +gallery} contains screenshots of every GTK+ widget, and links to their API +documentation.} +\es{GTK+ es una gran librería, y cubriendo en detalle aquí tomaría demasiado +tiempo. Hay varios buenos tutoriales para el uso de GTK+ en Python, disponible +en varios idiomas. Se recomienda que los lea y aplique los ejercicios que dan. +La \href{https://developer.gnome.org/gtk3/stable/ch03.html}{galería de widgets +de GTK+} contiene imágenes de todos los widgets de GTK+, y enlaces a la +documentación de la API.} + +\begin{frame}{\en{GTK+ tutorials}\es{Tutoriales de GTK+}} +\begin{itemize} + \item{\en{\url{https://developer.gnome.org/gnome-devel-demos/stable/tutorial.py.html.en}} + \es{\url{https://developer.gnome.org/gnome-devel-demos/stable/tutorial.py.html.es}}} + \item{\en{\url{https://developer.gnome.org/gnome-devel-demos/stable/beginner.py.html.en}} + \es{\url{https://developer.gnome.org/gnome-devel-demos/stable/beginner.py.html.es}}} + \item{\url{http://python-gtk-3-tutorial.readthedocs.org/en/latest/index.html}} + \item{\url{https://developer.gnome.org/gtk3/stable/ch03.html}} +\end{itemize} +\end{frame} + +\en{The GTK+ API documentation is currently only available for the C +programming language. However, converting function names between C and Python +is fairly simple, so you can use the C API documentation for Python.} +\es{La documentación del API de GTK+ sólo está disponible para el lenguaje de +programación C. Sin embargo, la conversión de nombres de funciones entre C y +Python es bastante simple, por lo que puede utilizar la documentación de la API +C con Python.} + +\en{To convert a C function name to a Python method name, remove underscores, +change it to camelcase, and separate `gtk', the class name, and the method +name. Python constructors become \texttt{*\_new()} functions in C. Constant +values are entirely capitalised in C, and only partially capitalised in +Python.} +\es{Para convertir un nombre de función C para un nombre de método Python, +retire subrayado, cambiar a CamelCase, y separado `gtk' del nombre de la clase y +del nombre del método. Constructores Python vuelven funciones \texttt{*\_new()} +en C. Valores constantes están completamente activados en C, y sólo parcialmente +capitalizado en Python.} + +\begin{frame}{\en{GTK+ API documentation}\es{Documentación de la API de GTK+}} +\begin{block}{} +\url{https://developer.gnome.org/gtk3/stable/gtkobjects.html} +\end{block} +\begin{block}{\en{Conversion}\es{Conversión}} +{\small\begin{align*} + \mathbf{Python} &\leftrightarrow \mathbf{C} \\ + \mathtt{Gtk.Window.set\_title()} &\leftrightarrow + \mathtt{gtk\_window\_set\_title()} \\ + \mathtt{Gtk.Button()} &\leftrightarrow \mathtt{gtk\_button\_new()} \\ + \mathtt{Gtk.ToggleButton.get\_active()} &\leftrightarrow + \mathtt{gtk\_toggle\_button\_get\_active()} \\ + \mathtt{Gtk.Orientation.VERTICAL} &\leftrightarrow + \mathtt{GTK\_ORIENTATION\_VERTICAL} +\end{align*}} +\end{block} +\end{frame} + + +\section{\en{Writing an activity}\es{Escribir una actividad}} + +\en{Fundamentally, a Sugar activity is a GTK+ application which provides a +single GTK+ \texttt{Window} widget for the activity to use. This window forms +the root of the activity's widget hierarchy, just as in a normal GTK+ +application. Events and callbacks are handled similarly.} +\es{Fundamentalmente, una actividad de Sugar es una aplicación de GTK+ que +proporciona un solo widget \texttt{Window} de GTK+ para la actividad de usar. +Esta ventana se forma la raíz de la jerarquía de widgets de la actividad, al +igual que en una aplicación normal de GTK+. Eventos y callbacks se manejan de +manera similar.} + +\en{To create an activity, subclass the +\texttt{sugar3.activity.activity.Activity} class +in Python. This \texttt{Activity} class provides a method to parent your +activity's widget tree: \texttt{set\_canvas()}. By creating a widget hierarchy +and passing it to this function, the interface for an activity can be created.} +\es{Para crear una actividad, debe subclase de la clase +\texttt{sugar3.activity.activity.Activity} en Python. Esta clase +\texttt{Activity} proporciona un método para adjuntar la jerarquía de widgets de +su actividad: \texttt{set\_canvas()}. Mediante la creación de una jerarquía de +widgets y pasarlo a esta función, se puede crear la interfaz para una +actividad.} + +\begin{frame}[fragile] +\frametitle{\en{Creating an activity UI}\es{Creación de una IU de la actividad}} +\begin{lstlisting}[language=Python,basicstyle={\ttfamily\small}] +from sugar3.activity import activity + +class HolaMundoActivity(activity.Activity): + def __init__(self, handle): + super(HolaMundoActivity, self).__init__(handle) + + box = Gtk.Box() + label = Gtk.Label('Hola Mundo!') + button = Gtk.Button('Boton') + + label.show() + box.add(label) + + button.show() + box.add(button) + + box.show() + self.set_canvas(box) +\end{lstlisting} +\end{frame} + +\en{When subclassing \texttt{sugar3.activity.activity.Activity}, three methods +must be implemented. \texttt{\_\_init()\_\_} is the normal object constructor, +and is called when your activity is started by the user. The \texttt{handle} +parameter provides the activity ID and access to sharing services (which aren't +covered here).} +\es{Al crear subclases de \texttt{sugar3.activity.activity.Activity}, tres +métodos se deben implementar. \texttt{\_\_init\_\_()} es el constructor de +objeto normal, y se llama cuando su actividad se inicia por el usuario. El +parámetro \texttt{handle} proporciona el ID de la actividad y el acceso a +servicios para compartir (que no se cubre en este manual).} + +\en{\texttt{read\_file} is called after \texttt{\_\_init\_\_} when resuming an +activity from the Journal. The \texttt{file\_path} parameter is the path of a +file containing the saved Journal data. Similarly, \texttt{write\_file} is +called when the user wants to save the activity to the Journal (either +explicitly, when closing the activity, or when switching to another activity), +and the \texttt{file\_path} is the path of a file which the Journal entry +should be saved to.} +\es{\texttt{read\_file} es llamada después \texttt{\_\_init\_\_} cuando se +reanuda la actividad en el Diario. El parámetro \texttt{file\_path} es la ruta +de un archivo que contiene los datos de diario guardados. Del mismo modo, +\texttt{write\_file} se llama cuando el usuario desea guardar la actividad con +el Diario (ya sea de manera explícita, al cerrar la actividad, o cuando se +cambia a otra actividad), y el \texttt{file\_path} es la ruta de un archivo que +la entrada de Diario debe ser guardado en.} + +\begin{frame}{\en{Required activity methods} + \es{Métodos necesarios para actividades}} +\begin{itemize} + \item{\texttt{\_\_init\_\_(self, handle)}} + \item{\texttt{read\_file(self, file\_path)}} + \item{\texttt{write\_file(self, file\_path)}} +\end{itemize} +\end{frame} + +\en{The \texttt{Activity} class provides several other methods (apart from +\texttt{set\_canvas()}) which can be called from within the activity code to +perform various tasks such as forcing the activity to be saved to the Journal, +closing the activity, and starting to share the activity on the network. Look +at the +\href{https://github.com/sugarlabs/sugar-toolkit-gtk3/blob/master/src/sugar3/activity/activity.py}{source code} for \texttt{sugar3.activity.activity.Activity} for +details.} +\es{La clase \texttt{Activity} ofrece varios métodos (además de +\texttt{set\_canvas()}), que se puede llamar desde dentro del código de +actividad para realizar diversas tareas, tales como obligar a la actividad que +se guardan en el Diario, el cierre de la actividad, y empezar a compartir la +actividad en la red. Mira +\href{https://github.com/sugarlabs/sugar-toolkit-gtk3/blob/master/src/sugar3/activity/activity.py}{el código} de +\texttt{sugar3.activity.activity.Activity} para más detalles.} + +\en{The most important thing to do in the \texttt{\_\_init\_\_} method is to +add a toolbar to the activity. Amongst other things, this adds a close button +to the activity.} +\es{La cosa más importante que hacer en el método \texttt{\_\_init\_\_} es +agregar una barra de herramientas a la actividad. Entre otras cosas, esto se +agrega un botón de cierre de la actividad.} + +\begin{frame}[fragile] +\frametitle{\en{Adding a toolbar}\es{Adición de una barra de herramientas}} +\begin{lstlisting}[language=Python] +def __init__(self, handle): + # Cree la caja de herramientas de + # actividad estandar. + toolbar_box = ToolbarBox() + self.set_toolbar_box(toolbar_box) + toolbar_box.show() + + main_toolbar = toolbar_box.toolbar + + activity_button = widgets.ActivityToolbarButton(self) + main_toolbar.insert(activity_button, 0) + activity_button.show() +\end{lstlisting} +\end{frame} + + +\section{\en{Packaging an activity}\es{Empaquetar una actividad}} + +\en{All the files for an activity are bundled together in a special format to +form a single \texttt{.xo} file which can be executed by the XO. An \texttt{.xo} +file is just a renamed Zip archive, but it must contain three key files: +\texttt{setup.py}, \texttt{activity/activity.info} and +\texttt{activity/activity.svg}.} +\es{Todos los archivos de una actividad se agrupan en un formato especial para +formar un único archivo \texttt{.xo} que puede ser ejecutado por el XO. Un +archivo \texttt{.xo} es sólo un archivo Zip cambiado de nombre, pero debe +contener tres archivos principales: \texttt{setup.py}, +\texttt{activity/activity.info} y \texttt{activity/activity.svg}.} + +\es{Los nombres de archivo en Inglés no se deben traducir al Español, como el +código de Sugar espera encontrar los nombres de los archivos exactos.} + +\begin{frame}{\en{XO bundle format}\es{Formato de los paquetes de XO}} +\begin{itemize}\item{\texttt{\en{ActivityName.activity}\es{NombreDeActividad.activity}}\begin{itemize} + \item{\texttt{\en{activityname.py}\es{nombredeactividad.py}}} + \item{\texttt{setup.py}} + \item{\texttt{activity/}\begin{itemize} + \item{\texttt{activity.info}} + \item{\texttt{activity.svg}} + \end{itemize}} + \item{\texttt{icons/}\begin{itemize} + \item{\en{any-custom-icons.svg}\es{los-iconos-personalizados.svg}} + \item{$\cdots$} + \end{itemize}} + \item{\texttt{po/}\begin{itemize} + \item{\texttt{de.po}} + \item{\texttt{es.po}} + \item{\texttt{it.po}} + \item{$\cdots$} + \item{\texttt{\en{ActivityName.pot}\es{NombreDeActividad.pot}}} + \end{itemize}} +\end{itemize}}\end{itemize} +\end{frame} + +\en{\texttt{activity.info} contains metadata about the activity, such as its +name, description, ID, version and software licence. \texttt{activity.svg} is +the icon for the activity. \texttt{setup.py} is used during development to build +and test the activity, and is the same for all activities. +\texttt{activityname.py} contains the code for the activity, and can have any +name --- the actual filename is referenced in \texttt{activity.info}.} +\es{\texttt{activity.info} contiene metadatos acerca de la actividad, tales como +su nombre, descripción, ID, la versión y licencia de software. +\texttt{activity.svg} es el icono de la actividad. \texttt{setup.py} se utiliza +durante el desarrollo para construir y probar la actividad, y es el mismo para +todas las actividades. \texttt{nombredeactividad.py} contiene el código para la +actividad, y puede tener cualquier nombre --- el nombre de archivo real se hace +referencia en la \texttt{activity.info}.} + +% TODO: Add a lstdefinelanguage for this if I get time. +\begin{frame}[fragile] +\frametitle{\texttt{activity.info}} +\begin{lstlisting} +[Activity] +name = Pascal Triangle +summary = Addition game using Pascal's triangle. +activity_version = 1 +host_version = 1 +bundle_id = hn.educatrachos.pascaltriangle +icon = activity +exec = sugar-activity pascaltriangle.PascalTriangleActivity +license = GPLv2+ +\end{lstlisting} +\end{frame} + +\begin{frame}[fragile] +\frametitle{\texttt{setup.py}} +\begin{lstlisting}[language=Python] +#!/usr/bin/env python +from sugar.activity import bundlebuilder +if __name__ == "__main__": + bundlebuilder.start() +\end{lstlisting} +\end{frame} + +\en{The \texttt{icons} directory is optional, and contains any custom icons +which your activity uses (for example, in toolbars). The XO ships a few standard +icons, but not many, so activities have to provide their own in many cases.} +\es{El directorio \texttt{icons} es opcional, y contiene los iconos +personalizados que utiliza su actividad (por ejemplo, en las barras de +herramientas). La XO proporciona unos iconos estándar, pero no muchos, por lo +que las actividades tienen que proporcionar su propia en muchos casos.} + +\en{The \texttt{po} directory is also optional (though highly recommended) and +contains translations of all the UI strings in the activity, so it can be run +in other languages. By convention, all UI strings in Python are written in +English --- so when writing an activity, you need to provide a Spanish +translation as \texttt{es.po}. \texttt{ActivityName.pot} is a template for the +\texttt{.po} files. Internationalisation will be covered in more detail later.} +\es{El directorio \texttt{po} también es opcional (aunque muy recomendable) y +contiene las traducciones de todas las cadenas de la IU en la actividad, por lo +que se puede ejecutar en otros idiomas. Por convención, todas las cadenas de la +IU en Python están escritos en Inglés --- así cuando se escribe una actividad, +es necesario proporcionar una traducción al Español como \texttt{es.po}. +\texttt{NombreDeActividad.pot} es una plantilla para los archivos \texttt{.po}. +Internacionalización se explica con más detalle más adelante.} + + +\section{\en{Version control}\es{Control de versiones}} + +\en{Creating a new activity starts with creating the directory structure for it, +then by setting up version control. Version control is a way of cataloguing the +history of development of some code by storing multiple \emph{revisions} of each +file. This allows examination of the changes between each revision (as the +software is developed), and also allows the code to be reverted to a previous +revision if problems are found in later code. Importantly, version control +systems make it easy to distribute code across the Internet, by \emph{pushing} +it to remote repositories.} +\es{Crear una nueva actividad se inicia con la creación de la estructura de +directorios para que, a continuación, mediante el establecimiento de control de +versiones. El control de versiones es una manera de catalogar la historia del +desarrollo de un código mediante el almacenamiento de múltiples +\emph{revisiones} de cada archivo. Esto permite que el examen de los cambios +entre cada revisión (como se desarrolla el software), y también permite que el +código para revertir a una revisión anterior si los problemas se encuentran en +el código más adelante. Es importante destacar que los sistemas de control de +versiones facilitan la distribución del código a través de Internet, +\emph{empujándolo} a los repositorios remotos.} + +\en{The recommended version control system for use with Sugar activities is +`git', a popular system used by many open source projects. There isn't +time to give a full introduction to git here, so only a few commands +will be demonstrated.} +\es{El sistema de control de versiones se recomienda su uso en las actividades +de Sugar es `git', un sistema popular y utilizado por muchos proyectos de +software libre. No hay tiempo para dar una introducción completa a git aquí, así +que sólo unos pocos comandos se demostrarán.} + +\en{Executed from a terminal, in the activity's directory, \texttt{git~init} +creates a new git repository. (This only needs to be perfomed once.) +\texttt{git~add} adds files to git's list of staged files, which can be seen by +running \texttt{git~status}. \texttt{git~commit} creates a new revision in the +repository, with the changes which were staged using \texttt{git~add}. The whole +repository can then be pushed to a server. \texttt{git~log} shows the existing +revisions in the repository.} +\es{Ejecutado desde un terminal, en el directorio de la actividad, +\texttt{git~init} crea un nuevo repositorio de git. (Necesario sólo una vez.) +\texttt{git~add} agrega archivos a la lista de archivos de git organizaron, que +se puede ver mediante la ejecución de \texttt{git~status}. \texttt{git~commit} +crea una nueva revisión en el repositorio, con los cambios que se organizaron +con \texttt{git~add}. Todo el repositorio puede entonces ser empujada a un +servidor. \texttt{git~log} muestra las revisiones existentes en el repositorio.} + +\begin{frame}{\en{Introduction to git}\es{Introducción a git}} +\begin{itemize} + \item{\texttt{git~init}} + \item{\texttt{git~add \en{file1.py file2.py}\es{archivo1.py archivo2.py} \dots}} + \item{\texttt{git~status}} + \item{\texttt{git~commit}} + \item{\texttt{git~log}} +\end{itemize} +\end{frame} + +\begin{frame}{\en{git resources}\es{Recursos para git}} +\begin{block}{\en{Introductions}\es{Introducciones}} +\begin{itemize} + \item{\url{http://try.github.io/}} + \item{\url{http://gitimmersion.com/}} +\end{itemize} +\end{block} +\begin{block}{\en{References}\es{Referencias}} +\begin{itemize} + \item{\url{http://git-scm.com/book\es{/es}}} + \item{\url{http://gitref.org/}} +\end{itemize} +\end{block} +\end{frame} + + +\en{Building the XO bundle is achieved using \texttt{setup.py}. When developing +locally, run \texttt{./setup.py~dev} from a terminal in the activity's directory +to set up the activity to run on your computer with \texttt{sugar-emulator} +(discussed later). To build the \texttt{.xo} file for distribution, run +\texttt{./setup.py~dist\_xo}. When building the \texttt{.xo} file, the script +will ignore files which aren't committed to git, so ensure all relevant files +(but not files which have been automatically generated) have been added to git +using \texttt{git~add}.} +\es{Construyendo el paquete XO se consigue utilizando \texttt{setup.py}. En el +desarrollo a nivel local, ejecute \texttt{./setup.py~dev} desde un terminal en +el directorio de la actividad para establecer la actividad se ejecute en su +equipo con \texttt{sugar-emulator} (explicado más adelante). Para generar el +archivo \texttt{.xo} para la distribución, ejecute \texttt{./setup.py~dist\_xo}. +Cuando se construye el fichero \texttt{.xo}, el script pasará por alto los +archivos que no se han añadido a git, para asegurar que todos los archivos +relevantes (pero no los archivos que se han generado de forma automática), se +han añadido git utilizando \texttt{git~add}.} + +\begin{frame}{\texttt{setup.py}} +\begin{itemize} + \item{\texttt{./setup.py~dev}} + \item{\texttt{./setup.py~dist\_xo}} +\end{itemize} +\end{frame} + + +\section{\en{Emulating Sugar for testing}\es{Emulando Sugar para probar}} + +\en{A recommended way to develop activities is to use \texttt{sugar-emulator}, +a program which can be installed on most desktop Linux distributions. It allows +the Sugar environment to be emulated on a desktop, meaning a new activity can +be tested without being copied over to a physical XO.} +\es{Una forma recomendada para el desarrollo de actividades es utilizar +\texttt{sugar-emulator}, un programa que se puede instalar en la mayoría de las +distribuciones de Linux. Permite el entorno azúcar a emular en un escritorio, lo +que significa una nueva actividad puede ser probado sin copiarse a un XO +físico.} + +\en{To run \texttt{sugar-emulator}, simply type its name into the terminal. For +extra debugging output, also set the \texttt{SUGAR\_LOG\_LEVEL} environment +variable. To run the emulator in a different language, set the \texttt{LANG} +environment variable.} +\es{Para ejecutar \texttt{sugar-emulator}, simplemente escriba su nombre en el +terminal. Para la salida de depuración extra, también establezca la variable de +entorno \texttt{SUGAR\_LOG\_LEVEL}. Para ejecutar el emulador en un idioma +diferente, establezca la variable de entorno \texttt{LANG}.} + +\begin{frame}{\texttt{sugar-emulator}} +\begin{itemize} + \item{\texttt{sugar-emulator}} + \item{\texttt{SUGAR\_LOG\_LEVEL=debug LANG=es sugar-emulator}} +\end{itemize} +\end{frame} + +\note{Give an interactive demo of \texttt{sugar-emulator} at this point.} + + +\en{Debugging an activity is similar to debugging any other Python program: the +simplest way is to use the \texttt{print()} function to print out values from +the program, and manually check whether they're what's expected --- or whether +those points in the program are reached at all.} +\es{Depuración de la actividad es similar a depurar cualquier otro programa de +Python: la forma más sencilla es utilizar la función \texttt{print()} para +imprimir los valores del programa, y comprobar manualmente si son lo que se +espera --- o si esos puntos en el programa se alcanzan en absoluto.} + +\en{When using \texttt{sugar-emulator}, text outputted using \texttt{print()} +won't appear in the normal terminal. Instead, it is saved to a log file in +\texttt{\textasciitilde/.sugar/default/logs} which is specific to the activity. +A new log file is created every time the activity is run in a single +\texttt{sugar-emulator} session, so the number $N$ changes.} +\es{Al usar \texttt{sugar-emulator}, texto emite utilizando \texttt{print()} no +aparecerá en el terminal normal. En su lugar, se guarda en un archivo de +registro en \texttt{\textasciitilde/.sugar/default/logs}, que es específica de +la actividad. Un nuevo archivo de registro se crea cada vez que la actividad se +ejecuta en una sola sesión de \texttt{sugar-emulator}, por lo que los cambios en +el número $N$.} + +\en{For a more flexible logging solution which doesn't have to be removed before +publishing the activity, use the +\href{http://docs.python.org/2/library/logging.html}{Python \texttt{logging} +module}. Create a \texttt{logger} object and call methods on it to print +messages with different severities.} +\es{Para una solución de registro más flexible que no tiene que ser removido +antes de la publicación de la actividad, el uso del +\href{http://docs.python.org/2/library/logging.html}{módulo \texttt{logging} de +Python}. Crear un objeto \texttt{logger} y llamar a métodos en él para imprimir +mensajes con diferentes niveles de gravedad.} + +\begin{frame}[fragile] +\frametitle{\en{Sugar logging}\es{Registro en Sugar}} +\begin{block}{\en{Log files}\es{Archivos de registro}} +{\large{\texttt{\textasciitilde/.sugar/default/logs/\en{activity.id}\es{actividad.id}-$N$.log}}} +\end{block} +\begin{block}{\en{Logging code}\es{Código de registro}} +\begin{lstlisting}[language=Python] +import logging + +self._logger = logging.getLogger('nombre-de-mi-actividad') + +self._logger.error('Este es un error') +self._logger.warning('...una advertencia') +self._logger.debug('...un mensaje de depuracion') +\end{lstlisting} +\end{block} +\end{frame} + + +\section{\en{Internationalisation}\es{Internationalisation}} + +\en{Internationalisation is an important part of writing an activity, as it +allows your activity to be used in other languages. Internationalisation is +mostly about translation, but other things must be considered (such as +currencies, date formats, and whether text is written left-to-right or +right-to-left). Adding translation support to an activity is easier; the others +are more complex and are not covered here.} +\es{La internacionalización es una parte importante de la escritura una +actividad, ya que permite que la actividad que se utilizará en otros idiomas. La +internacionalización es sobre todo acerca de la traducción, pero otras cosas se +debe considerar (como monedas, formatos de fecha y si el texto se escribe de +izquierda a derecha o de derecha a izquierda). Adición de apoyo a la traducción +de una actividad es más fácil; los otros son más complejos y no están cubiertos +aquí.} + +\en{To add translation support, a library called \texttt{gettext} is used. For +each UI string to be translated, the English string is passed through the +\texttt{\_} (underscore) function provided by \texttt{gettext}, which returns +either a translated version, or the original string if no translation is +available.} +\es{Para añadir soporte de traducción, se utiliza una librería llamada +\texttt{gettext}. Para cada cadena de IU sea traducida, la cadena de Inglés se +pasa a través de la función \texttt{\_} (guión bajo) proporcionado por +\texttt{gettext}, que devuelve una versión traducida, o la cadena original si no +hay traducción disponible.} + +\begin{frame}[fragile] +\frametitle{\en{Translation support}\es{Apoyo a la traducción}} +\begin{lstlisting}[language=Python] +from gettext import gettext as _ + +# Previoso: Gtk.Button('Hello world!') +button = Gtk.Button(_('Hello world!')) +\end{lstlisting} +\end{frame} + +\en{In addition to these code changes, a set of \texttt{.po} translation files +have to be created. These give the translations of the English strings into +other languages, one file per language. Each file is written manually by a human +translator, working from a \texttt{.pot} template file. This \texttt{.pot} file +must be periodically updated to reflect changes in the strings marked for +translation in the program code.} +\es{Además de estos cambios en el código, un conjunto de archivos de traducción +\texttt{.po} tienen que ser creados. Estos dan las traducciones de las cadenas +en Inglés a otros idiomas, un archivo por cada idioma. Cada archivo se escribe +manualmente por un traductor humano, trabajando desde un archivo de plantilla +\texttt{.pot}. Este archivo \texttt{.pot} debe actualizarse periódicamente para +reflejar los cambios en las cuerdas marcadas para la traducción en el código del +programa.} + +\en{To generate the \texttt{.pot} file, run \texttt{./setup.py~genpot}. You can +then copy the \texttt{.pot} file to (for example) \texttt{es.po} and write the +Spanish translation. Don't forget to commit both files to git.} +\es{Para generar el archivo \texttt{.pot}, ejecutar \texttt{./setup.py~genpot}. +A continuación, puede copiar el archivo \texttt{.pot} a (por ejemplo) +\texttt{es.po} y escribir la traducción en Español. No te olvides de añadir los +dos archivos a git.} + +\begin{frame}{\en{Generating a POT}\es{Generación de un POT}} +\begin{itemize} + \item{\texttt{./setup.py genpot}} + \item{\texttt{cd po}} + \item{\texttt{cp \en{ActivityName}\es{NombreDeActividad}.pot es.po}} + \item{\en{Edit \texttt{es.po} to create the Spanish translation.} + \es{Editar \texttt{es.po} para crear la traducción en Español}} +\end{itemize} +\end{frame} + +\note{Give an interactive example of generating a POT file and changing it to a +PO file now.} + +\en{Activities whose source code is hosted on \url{http://git.sugarlabs.org} can +use a web-based service called Pootle to get translations from teams all over +the world. This is a valuable service, and more information about setting it up +is available online.} +\es{Actividades cuyo código está alojado en \url{http://git.sugarlabs.org} +pueden utilizar un servicio basado en web llamado Pootle para obtener +traducciones de los equipos de todo el mundo. Este es un servicio valioso, y más +información sobre su puesta en marcha está disponible en línea.} + +\begin{frame}{\en{Adding Pootle support}\es{Añadir soporte de Pootle}} +\begin{block}{\en{Reference}\es{Referencía}} +\en{\url{http://en.flossmanuals.net/make-your-own-sugar-activities/going-international-with-pootle/}} +\es{\url{http://en.flossmanuals.net/como-hacer-una-actividad-sugar/internacionalizarse-con-pootle-god-100/}} +\end{block} +\begin{block}{\en{Overview}\es{Visión de conjunto}} +\begin{enumerate} + \item{\en{Push activity code to git.sugarlabs.org, as described below.} + \es{Empuje código de actividad a git.sugarlabs.org, tal como se + describe a continuación.}} + \item{\en{Allow the `pootle' user to commit to git.} + \es{Permitir que el usuario `pootle' para crear commites en git.}} + \item{\en{File a bug report requesting Pootle support for your project.} + \es{Presentar un informe de error solicitando apoyo Pootle para su + proyecto.}} +\end{enumerate} +\end{block} +\end{frame} + + +\section{\en{Publishing an activity}\es{Publicar una actividad}} + +\en{After finishing the activity, testing it on relevant versions of the XO (in +emulation and on physical machines), and generating a \texttt{.xo} bundle, the +activity needs to be published to \url{http://activities.sugarlabs.org} for +users to download.} +\es{Después de terminar la escritura de la actividad, la probación en las +versiones pertinentes de la XO (en la emulación y en máquinas físicas), y la +generación de un paquete de \texttt{.xo}, la actividad tiene que ser publicada a +\url{http://activities.sugarlabs.org/es-ES/} para que los usuarios descargar.} + +\en{Before publishing the activity, its source code must be made available on +\url{http://git.sugarlabs.org} so that others can view it and improve on it. +Educatrachos has \href{https://git.sugarlabs.org/+educatrachos}{a team page} on +that website, and anyone from Educatrachos who is writing an activity should +become a member of the team. An administrator (like me) can do that.} +\es{Antes de la publicación de la actividad, su código debe estar disponible en +\url{http://git.sugarlabs.org} para que otros puedan verlo y mejorar en él. +Educatrachos tiene +\href{https://git.sugarlabs.org/+educatrachos}{una página del equipo} en ese +sitio web, y cualquier persona de Educatrachos que está escribiendo una +actividad debe convertirse en un miembro del equipo. Un administrador (como yo) +puede hacer eso.} + +\en{To add an activity to \url{http://git.sugarlabs.org}, add a new project for +it, then create a repository in that project. Name both after the activity. Once +the repository's been created, add it as a \texttt{remote} called +\texttt{origin} in your local git repository, then push the \texttt{master} +branch to it. Whenever you commit to the local repository from that point +onwards, you must subsequently push the commit to the remote so that it is +visible online.} +\es{Para añadir una actividad a \url{http://git.sugarlabs.org}, agregue un nuevo +proyecto para que, a continuación, crear un repositorio en ese proyecto. Nombra +dos después de la actividad. Después ha creado el repositorio, añadirlo como el +\texttt{remote} se llama \texttt{origin} en su repositorio git local, empujar la +rama \texttt{master} a ella. Cada vez que se crea un commit en el repositorio +local de ese punto en adelante, debe posteriormente empujar el commit con el +mando a distancia para que sea visible en Internet.} + +\begin{frame}{\en{Publishing activity source code} + \es{Publicación del código de una actividad}} +\begin{enumerate} + \item{\en{Register on \href{http://git.sugarlabs.org}{git.sugarlabs.org}:} + \es{Registrarse en + \href{http://git.sugarlabs.org}{git.sugarlabs.org}:} + \url{https://git.sugarlabs.org/users/new}} + \item{\en{Have your account added to the Educatrachos team:} + \es{Haga que su cuenta agregada al equipo Educatrachos:} + \url{https://git.sugarlabs.org/+educatrachos/memberships/new}} + \item{\en{Create a new project owned by the Educatrachos team:} + \es{Crear un nuevo proyecto de propiedad del equipo Educatrachos:} + \url{https://git.sugarlabs.org/projects/new}} + \item{\en{Add a new repository to the project. Enable merge requests so + others can suggest changes to the code.} + \es{Añadir un nuevo repositorio para el proyecto. Permitir solicitudes + de fusiones para que otros pueden sugerir cambios en el código.}} + \item{\en{Copy the `SSH' URI from ``Clone \& push URLs'' on the repository + page. e.g.\ \url{gitorious@git.sugarlabs.org:pascal-triangle/pascal-triangle.git}} + \es{Copie el URI `SSH' desde ``Clone \& push URLs'' en la página del + repositorio. Por ejemplo, + \url{gitorious@git.sugarlabs.org:pascal-triangle/pascal-triangle.git}}} + \item{\en{In a terminal:}\es{En un terminal:} + \texttt{cd \en{path/to/my-activity}\es{camino/a/mi-actividad}}} + \item{\texttt{git~remote add origin \emph{SSH URI}}} + \item{\texttt{git~push -u origin master}} +\end{enumerate} +\end{frame} + +\en{With the source code published online, the activity can be added to +\url{http://activities.sugarlabs.org}. You must register an account on that +website, then join the +\href{http://activities.sugarlabs.org/en-US/developers}{Developer Hub} and follow +the process to submit a new activity.} +\es{Con el código fuente publicada en línea, la actividad se puede añadir a +\url{http://activities.sugarlabs.org/es-ES/}. Debe registrar una cuenta en ese +sitio web, y luego unirse el Centro de Desarrollo y seguir el proceso para +enviar una nueva actividad.} + +\en{Newly submitted activities are initially marked as private. Once enough +details have been filled out for an activity, it is moved to the sandbox, when +users can start downloading it. Once enough users have downloaded and rated the +activity, it can be peer-reviewed and promoted to public status.} +\es{Actividades recién enviados inicialmente se marcan como privados. Una vez +que suficientes detalles se han llenado de una actividad, se trasladó a la caja +de arena, cuando los usuarios pueden empezar a descargarlo. Una vez que +suficientes usuarios han descargado y evaluado la actividad, puede ser revisada +por pares y promovido a la condición pública.} + +\begin{frame}{\en{Publishing an activity bundle} + \es{Publicación de un paquete de una actividad}} +\begin{enumerate} + \item{\en{Register on + \href{http://activities.sugarlabs.org}{activities.sugarlabs.org}: + \url{http://activities.sugarlabs.org/en-US/sugar/users/register}} + \es{Registrarse en: + \href{http://activities.sugarlabs.org/es-ES/} + {activities.sugarlabs.org}: + \url{http://activities.sugarlabs.org/es-ES/sugar/users/register}}} + \item{\en{Join the `Developer Hub': + \url{http://activities.sugarlabs.org/en-US/developers}} + \es{Únete a la `Centro de desarrolladores': + \url{http://activities.sugarlabs.org/es-ES/developers}}} + \item{\en{Follow the process to submit a new activity: + \url{http://activities.sugarlabs.org/en-US/developers/addon/submit}} + \es{Siga el proceso para enviar una nueva actividad: + \url{http://activities.sugarlabs.org/es-ES/developers/addon/submit}}} +\end{enumerate} +\end{frame} + + +\section{\en{Conclusion}\es{Conclusión}} + +\en{In summary: one of the key aims of writing your own activities should be to +work in partnership with the worldwide Sugar and OLPC community. This is +sometimes called ``working upstream''. They are happy to answer questions and +help solve problems, and in return they would be happy to receive new activities +and contributions which can be re-used by other OLPC deployments. As with any +community, the tighter people integrate, the better the results for everyone.} +\es{En resumen: uno de los objetivos principales de escribir sus propias +actividades debería ser trabajar en colaboración con la comunidad mundial de +Sugar y OLPC. Esto a veces se llama ``trabajando río arriba''. Ellos están +dispuestos a responder preguntas y ayudar a resolver problemas, y en cambio +estarían felices de recibir las nuevas actividades y las contribuciones que +pueden ser reutilizados por otros despliegues de OLPC. Al igual que con +cualquier comunidad, el pueblo más estrictas integran, mejores serán los +resultados para todos.} + +\en{This is the end of the training, but not the end of the learning. I +encourage you to practice everything you've learned by writing activities. The +best way to learn programming is through practice. I am happy to answer +absolutely any questions either in person or by e-mail, even after I've left +Honduras. I would be thrilled to help get activities published by Educatrachos +once I return to the UK.} +\es{Este es el final de la capacitación, pero no el final del aprendizaje. Les +animo a practicar todo lo que has aprendido al escribir algunas actividades. La +mejor manera de aprender es a través de la práctica de programación. Estoy +encantado de responder a cualquier pregunta en absoluto, ya sea en persona o por +e-mail, incluso después de que me he dejado Honduras. Yo estaría encantado de +ayudar a que las actividades publicadas por Educatrachos cuando regreso al +Reino~Unido.} + +\note{After a break, it would be a good idea to give an interactive demo of +creating an entire activity from scratch.} + + +\section{\en{Miscellany}\es{Miscelánea}} + +\en{Again, not all the features of Sugar can be covered +in the available time. Here are the topics which haven't been covered, along +with links to relevant documentation. Writing activities in HTML5 wasn't covered +because the version of Sugar deployed in Honduras is too old to support them.} +\es{Una vez más, no todas las características de Sugar se pueden cubrir en el +tiempo disponible. Estos son los temas que no han sido cubiertos, así como +enlaces a la documentación pertinente. Las actividades de escritura en HTML5 no +estaba cubierto por la versión de Sugar desplegado en Honduras es demasiado +viejo para apoyarlos.} + +\begin{frame}{\en{What's missing}\es{Temas no abarcados}} +\begin{itemize} + \item{\en{Drawing custom widgets with Cairo:} + \es{Dibujo widgets personalizados con Cairo:} + % FIXME: This should actually be the following, but it doesn't exist yet: + % https://developer.gnome.org/gnome-devel-demos/unstable/widget_drawing.py.html.en + \href{http://tecnocode.co.uk/misc/platform-demos/widget_drawing.py.xhtml}{(1)}, + \href{http://www.tortall.net/mu/wiki/CairoTutorial}{(2)}, + \href{https://sites.google.com/site/randomcodecollections/home/python-gtk-3-pango-cairo-example}{(3)}, + \href{http://ptomato.name/advanced-gtk-techniques/html/custom-container.html}{(4)}, + \href{http://lotsofexpression.blogspot.com/2012/04/python-gtk-3-example-implementing-cairo.html}{(5)}} + \item{\en{Shared activities:}\es{Actividades compartidas:} + \en{\href{http://en.flossmanuals.net/make-your-own-sugar-activities/making-shared-activities/}{(1)}} + \es{\href{http://en.flossmanuals.net/como-hacer-una-actividad-sugar/making-shared-activities-vc/}{(1)}}} + \item{\en{Text-to-speech:}\es{Texto a voz:} + \en{\href{http://en.flossmanuals.net/make-your-own-sugar-activities/adding-text-to-speech/}{(1)}} + \es{\href{http://en.flossmanuals.net/como-hacer-una-actividad-sugar/adding-text-to-speach/}{(1)}}} + \item{\en{Games with PyGame:}\es{Juegos con PyGame:} + \en{\href{http://en.flossmanuals.net/make-your-own-sugar-activities/making-activities-using-pygame/}{(1)}} + \es{\href{http://en.flossmanuals.net/como-hacer-una-actividad-sugar/construir-actividades-usando-pygame/}{(1)}}} + \item{HTML5: + \href{http://developer.sugarlabs.org/web-architecture.md.html}{(1)}} +\end{itemize} +\end{frame} + + +\begin{frame}{\en{Links}\es{Enlaces}} +\begin{block}{\en{Important links}\es{Enlaces importantes}} +\begin{itemize} + \item{\en{\url{http://en.flossmanuals.net/make-your-own-sugar-activities/}} + \es{\url{http://en.flossmanuals.net/como-hacer-una-actividad-sugar/heredar-activity-de-sugaractivity-jm-50/}}} + \item{\url{http://python-gtk-3-tutorial.readthedocs.org/en/}} + \item{\url{http://doc.sugarlabs.org/epydocs/}} +\end{itemize} +\end{block} +\begin{block}{\en{Other links}\es{Enlaces otros}} +\begin{itemize} + \item{\url{http://wiki.sugarlabs.org/go/Features/GTK3/Porting}} + \item{\url{http://wiki.sugarlabs.org/go/Human_Interface_Guidelines/The_Sugar_Interface}} + \item{\url{http://wiki.sugarlabs.org/go/Development_Team/Almanac}} + \item{\url{http://wiki.sugarlabs.org/go/Activity_Team}} +\end{itemize} +\end{block} +\end{frame} + + +\begin{frame}<presentation>{\en{Questions?}\es{¿Preguntas?}} +\en{Any questions so far?} +\es{¿Hay preguntas hasta ahora?} +\end{frame} |