Changes

Jump to navigation Jump to search
Created page with '[http://git.sugarlabs.org/projects/ruler/repos/mainline/trees/master Ruler] is a simple activity that uses Cairo graphics. It is also an example of how to use both the new (0.86+…'
[http://git.sugarlabs.org/projects/ruler/repos/mainline/trees/master Ruler] is a simple activity that uses Cairo graphics. It is also an example of how to use both the new (0.86+) and old (pre-0,86) toolbar, and simple Journal interaction. Not the more beautiful code, but it works.

Misc. imports. Note that we catch an exception if the new 0.86 toolbars aren't available.
<pre>
import pygtk
pygtk.require('2.0')
import gtk
import gobject
import cairo
import os.path

import sugar
from sugar.activity import activity
try: # 0.86+ toolbar widgets
from sugar.bundle.activitybundle import ActivityBundle
from sugar.activity.widgets import ActivityToolbarButton
from sugar.activity.widgets import StopButton
from sugar.graphics.toolbarbox import ToolbarBox
from sugar.graphics.toolbarbox import ToolbarButton
except ImportError:
pass
from sugar.graphics.toolbutton import ToolButton
from sugar.graphics.menuitem import MenuItem
from sugar.graphics.icon import Icon
from sugar.datastore import datastore
try:
from sugar.graphics import style
GRID_CELL_SIZE = style.GRID_CELL_SIZE
except:
GRID_CELL_SIZE = 0

import logging
_logger = logging.getLogger("ruler-activity")

from gettext import gettext as _

import util
import show_rulers
import show_grids
import show_checkers
import show_angles

SERVICE = 'org.sugarlabs.RulerActivity'
IFACE = SERVICE
PATH = '/org/augarlabs/RulerActivity'
</pre>

The Cairo canvas event handler. All the drawing happens in here.

<pre>

# Create a GTK+ widget on which we will draw using Cairo
class MyCanvas(gtk.DrawingArea):

def __init__(self):
gtk.DrawingArea.__init__(self)
self._draw_ruler = False
self._object = None
self.connect('expose-event', self.__expose_event_cb)
self.dpi = 200

def __expose_event_cb(self, drawing_area, event):
cr = self.window.cairo_create()

if self._draw_ruler:
# draw lines to create a star
self._object.draw(cr,self._dpi)

# Restrict Cairo to the exposed area; avoid extra work
cr.rectangle(event.area.x, event.area.y,
event.area.width, event.area.height)
cr.clip()

def add_a_ruler(self,r):
self._draw_ruler = True
self._object = r
self.queue_draw()

def get_dpi(self):
return self._dpi

def set_dpi(self, dpi):
self._dpi = dpi

</pre>

The main activity.

<pre>
#
# Sugar activity
#
class RulerActivity(activity.Activity):

def __init__(self, handle):
super(RulerActivity,self).__init__(handle)

_font = 'helvetica 12'
_font_bold = 'helvetica bold 12'

#
# We need a canvas
#
self._canvas = MyCanvas()
self.set_canvas(self._canvas)
self._canvas.show()

</pre>

How to find out the size of the canvas.

<pre>

_width = gtk.gdk.screen_width()
_height = gtk.gdk.screen_height()-GRID_CELL_SIZE

</pre>

Check to see if there is metadata available. Since we are not using file data, we don't need to use <code>read_file</code>

<pre>
# Read the dpi from the Journal
try:
dpi = self.metadata['dpi']
_logger.debug("Read dpi: " + str(dpi))
self._canvas.set_dpi(int(dpi))
except:
if os.path.exists('/sys/power/olpc-pm'):
self._canvas.set_dpi(200) # OLPC XO
else:
self._canvas.set_dpi(100) # Just a guess

</pre>

Initialize the subclasses used for drawing.

<pre>

# Create instances of our graphics
self._r = show_rulers.ScreenOfRulers(_font,_font_bold,_width,_height)
self._gcm = show_grids.ScreenGrid_cm(_font,_font_bold,_width,_height)
self._gmm = show_grids.ScreenGrid_mm(_font,_font_bold,_width,_height)
self._a90 = show_angles.Angles90(_font,_font_bold,_width,_height)
self._a360 = show_angles.Angles360(_font,_font_bold,_width,_height)
self._c = show_checkers.ScreenOfCircles(_font,_font_bold,_width,_height)

# start with a ruler
self._current = self._r
self._canvas.add_a_ruler(self._current)

# other settings
self._grids_mode = "cm"
self._angles_mode = "90"
</pre>

We'll get a NameError if the new toolbars are not available.

<pre>
#
# We need some toolbars
#
try:
# Use 0.86 toolbar design
toolbar_box = ToolbarBox()

# Buttons added to the Activity toolbar
activity_button = ActivityToolbarButton(self)
toolbar_box.toolbar.insert(activity_button, 0)
activity_button.show()

# Show rulers
self.rulers = ToolButton( "ruler" )
self.rulers.set_tooltip(_('Ruler'))
self.rulers.props.sensitive = True
self.rulers.connect('clicked', self._rulers_cb)
toolbar_box.toolbar.insert(self.rulers, -1)
self.rulers.show()

# Show grids
self.grids = ToolButton( "grid-a" )
self.grids.set_tooltip(_('Grid'))
self.grids.props.sensitive = True
self.grids.connect('clicked', self._grids_cb)
toolbar_box.toolbar.insert(self.grids, -1)
self.grids.show()

# Show angles
self.angles = ToolButton( "angles-90" )
self.angles.set_tooltip(_('Angles'))
self.angles.props.sensitive = True
self.angles.connect('clicked', self._angles_cb)
toolbar_box.toolbar.insert(self.angles, -1)
self.angles.show()

# Show checker
self.checker = ToolButton( "checker" )
self.checker.set_tooltip(_('Checker'))
self.checker.props.sensitive = True
self.checker.connect('clicked', self._checker_cb)
toolbar_box.toolbar.insert(self.checker, -1)
self.checker.show()

separator = gtk.SeparatorToolItem()
separator.show()
toolbar_box.toolbar.insert(separator, -1)

dpi = self._canvas.get_dpi()
self._dpi_spin_adj = gtk.Adjustment(dpi, 72, 200, 2, 32, 0)
self._dpi_spin = gtk.SpinButton(self._dpi_spin_adj, 0, 0)
self._dpi_spin_id = self._dpi_spin.connect('value-changed',
self._dpi_spin_cb)
self._dpi_spin.set_numeric(True)
self._dpi_spin.show()
self.tool_item_dpi = gtk.ToolItem()
self.tool_item_dpi.add(self._dpi_spin)
toolbar_box.toolbar.insert(self.tool_item_dpi, -1)
self.tool_item_dpi.show()

separator = gtk.SeparatorToolItem()
separator.props.draw = False
separator.set_expand(True)
separator.show()
toolbar_box.toolbar.insert(separator, -1)

# The ever-present Stop Button
stop_button = StopButton(self)
stop_button.props.accelerator = '<Ctrl>Q'
toolbar_box.toolbar.insert(stop_button, -1)
stop_button.show()

self.set_toolbar_box(toolbar_box)
toolbar_box.show()

</pre>

The old toolbars...

<pre>
except NameError:
# Use pre-0.86 toolbar design
toolbox = activity.ActivityToolbox(self)
self.set_toolbox(toolbox)

self.projectToolbar = ProjectToolbar(self)
toolbox.add_toolbar( _('Rulers'), self.projectToolbar )

toolbox.show()
toolbox.set_current_toolbar(1)
</pre>

Without this <code>show_all()</code> the toolbars won't be drawn.

<pre>

self.show_all()

</pre>

Button call-backs that talk to the Cairo canvas

<pre>
#
# Button callbacks
#
def _rulers_cb(self, button):
self._current = self._r
self._canvas.add_a_ruler(self._current)
return True

def _grids_cb(self, button):
if self._grids_mode == "cm":
self._current = self._gcm
self.grids.set_icon("grid-c")
self._grids_mode = "mm"
else:
self._current = self._gmm
self.grids.set_icon("grid-a")
self._grids_mode = "cm"
self._canvas.add_a_ruler(self._current)
return True

def _angles_cb(self, button):
if self._angles_mode == "90":
self._current = self._a90
self.angles.set_icon("angles-360")
self._angles_mode = "360"
else:
self._current = self._a360
self.angles.set_icon("angles-90")
self._angles_mode = "90"
self._canvas.add_a_ruler(self._current)
return True

def _checker_cb(self, button):
self._current = self._c
self._canvas.add_a_ruler(self._current)
return True

def _dpi_spin_cb(self, button):
self._canvas.set_dpi(self._dpi_spin.get_value_as_int())
self._canvas.add_a_ruler(self._current)
return
</pre>

Saving metadata to the Journal: <code>write_file</code> gets called automatically when your activity is exited.

<pre>
"""
Write the dpi to the Journal
"""
def write_file(self, file_path):
dpi = self._canvas.get_dpi()
_logger.debug("Write dpi: " + str(dpi))
self.metadata['dpi'] = str(dpi)
</pre>

This code handles the pre-0.86 toolbars

<pre>
#
# Project toolbar for pre-0.86 toolbars
#
class ProjectToolbar(gtk.Toolbar):

def __init__(self, pc):
gtk.Toolbar.__init__(self)
self.activity = pc

# Ruler
self.activity.rulers = ToolButton( "ruler" )
self.activity.rulers.set_tooltip(_('Ruler'))
self.activity.rulers.props.sensitive = True
self.activity.rulers.connect('clicked', self.activity._rulers_cb)
self.insert(self.activity.rulers, -1)
self.activity.rulers.show()

# Grid
self.activity.grids = ToolButton( "grid-a" )
self.activity.grids.set_tooltip(_('Grid'))
self.activity.grids.props.sensitive = True
self.activity.grids.connect('clicked', self.activity._grids_cb)
self.insert(self.activity.grids, -1)
self.activity.grids.show()

# Angles
self.activity.angles = ToolButton( "angles-90" )
self.activity.angles.set_tooltip(_('Angles'))
self.activity.angles.props.sensitive = True
self.activity.angles.connect('clicked', self.activity._angles_cb)
self.insert(self.activity.angles, -1)
self.activity.angles.show()

# Checker
self.activity.checker = ToolButton( "checker" )
self.activity.checker.set_tooltip(_('Checker'))
self.activity.checker.props.sensitive = True
self.activity.checker.connect('clicked', self.activity._checker_cb)
self.insert(self.activity.checker, -1)
self.activity.checker.show()

separator = gtk.SeparatorToolItem()
separator.set_draw(True)
self.insert(separator, -1)
separator.show()

dpi = self.activity._canvas.get_dpi()
self.activity._dpi_spin_adj = gtk.Adjustment(dpi, 72, 200, 2, 32, 0)
self.activity._dpi_spin = \
gtk.SpinButton(self.activity._dpi_spin_adj, 0, 0)
self.activity._dpi_spin_id = self.activity._dpi_spin.connect(
'value-changed', self.activity._dpi_spin_cb)
self.activity._dpi_spin.set_numeric(True)
self.activity._dpi_spin.show()
self.activity.tool_item_dpi = gtk.ToolItem()
self.activity.tool_item_dpi.add(self.activity._dpi_spin)
self.insert(self.activity.tool_item_dpi, -1)
self.activity.tool_item_dpi.show()

</pre>

Navigation menu