# Copyright (c) 2007 Mitchell N. Charity
# Copyright (c) 2009-2012 Walter Bender
# Copyright (c) 2012 Flavio Danesse
#
# This file is part of Ruler.
#
# Ruler 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.
#
# Ruler 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 Ruler. If not, see
import gi
from gi.repository import Gtk
from gi.repository import GObject
from gi.repository import GdkX11
import cairo
import os.path
import sugar3
from sugar3.activity import activity
from sugar3.graphics.toolbarbox import ToolbarBox
from sugar3.bundle.activitybundle import ActivityBundle
from sugar3.activity.widgets import ActivityToolbarButton
from sugar3.activity.widgets import StopButton
from sugar3.graphics.toolbarbox import ToolbarButton
from sugar3.graphics.radiotoolbutton import RadioToolButton
from sugar3.graphics.toolbutton import ToolButton
from sugar3.graphics.menuitem import MenuItem
from sugar3.graphics.icon import Icon
from sugar3.datastore import datastore
from sugar3.graphics import style
GRID_CELL_SIZE = style.GRID_CELL_SIZE
import logging
_logger = logging.getLogger("ruler-activity")
from gettext import gettext as _
from util import calc_dpi
import show_rulers
import show_grids
import show_checkers
import show_angles
from sugar3.graphics import style
class MyCanvas(Gtk.DrawingArea):
''' Create a GTK+ widget on which we will draw using Cairo '''
def __init__(self):
Gtk.DrawingArea.__init__(self)
self._draw_ruler = False
self._object = None
self.connect('draw', self.__expose_event_cb)
self._dpi = 96
def __expose_event_cb(self, drawing_area, event):
cr = self.get_property('window').cairo_create()
if self._draw_ruler:
self._object.draw(cr, self._dpi)
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
#
# Sugar activity
#
class RulerActivity(activity.Activity):
def __init__(self, handle):
super(RulerActivity, self).__init__(handle)
self.button_dict = {}
self.callback_dict = {}
self._ready = False
font = 'helvetica 12'
font_bold = 'helvetica bold 12'
#
# We need a canvas
#
self._canvas = MyCanvas()
self.set_canvas(self._canvas)
self._canvas.show()
screen = GdkX11.X11Screen()
width = screen.width()
height = screen.height() - GRID_CELL_SIZE
dpi, self.known_dpi = calc_dpi()
self._canvas.set_dpi(dpi)
# 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"
#
# We need some toolbars
#
self.max_participants = 1
toolbar_box = ToolbarBox()
# Buttons added to the Activity toolbar
activity_button = ActivityToolbarButton(self)
toolbar_box.toolbar.insert(activity_button, 0)
activity_button.show()
self.rulers = radio_factory('ruler',
toolbar_box.toolbar,
self._rulers_cb,
tooltip=_('Ruler'),
group=None)
self.grids = radio_factory('grid-a',
toolbar_box.toolbar,
self._grids_cb,
tooltip=_('Grid'),
group=self.rulers)
self.angles = radio_factory('angles-90',
toolbar_box.toolbar,
self._angles_cb,
tooltip=_('Angles'),
group=self.rulers)
self.checker = radio_factory('checker',
toolbar_box.toolbar,
self._checker_cb,
tooltip=_('Checker'),
group=self.rulers)
if not self.known_dpi:
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 = 'Q'
toolbar_box.toolbar.insert(stop_button, -1)
stop_button.show()
self.set_toolbar_box(toolbar_box)
toolbar_box.show()
self.show_all()
# Restore state if previously saved
self._ready = True
if 'ruler' in self.metadata and \
self.metadata['ruler'] in self.button_dict:
_logger.debug('restoring %s', self.metadata['ruler'])
self.button_dict[self.metadata['ruler']].set_active(True)
self.callback_dict[self.metadata['ruler']]
else:
self._rulers_cb()
self.rulers.set_active(True)
#
# Button callbacks
#
def _rulers_cb(self, button=None):
if self._ready:
self._current = self._r
self._canvas.add_a_ruler(self._current)
_logger.debug('selecting ruler')
self.metadata['ruler'] = 'ruler'
return False
def _grids_cb(self, button=None):
if self._ready:
if self._grids_mode == "cm":
self._current = self._gcm
if hasattr(self, 'grids'):
self.grids.set_icon_name("grid-c")
self._grids_mode = "mm"
else:
self._current = self._gmm
if hasattr(self, 'grids'):
self.grids.set_icon_name("grid-a")
self._grids_mode = "cm"
self._canvas.add_a_ruler(self._current)
_logger.debug('selecting grids')
self.metadata['ruler'] = 'grids'
return False
def _angles_cb(self, button=None):
if self._ready:
if self._angles_mode == "90":
self._current = self._a90
if hasattr(self, 'angles'):
self.angles.set_icon_name("angles-360")
self._angles_mode = "360"
else:
self._current = self._a360
if hasattr(self, 'angles'):
self.angles.set_icon_name("angles-90")
self._angles_mode = "90"
self._canvas.add_a_ruler(self._current)
_logger.debug('selecting angles')
self.metadata['ruler'] = 'angles'
return False
def _checker_cb(self, button=None):
if self._ready:
self._current = self._c
self._canvas.add_a_ruler(self._current)
_logger.debug('selecting checker')
self.metadata['ruler'] = 'checker'
return False
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
def write_file(self, file_path):
''' Write the dpi to the Journal '''
dpi = self._canvas.get_dpi()
_logger.debug("Write dpi: " + str(dpi))
self.metadata['dpi'] = str(dpi)
def radio_factory(icon_name, toolbar, callback, cb_arg=None,
tooltip=None, group=None):
''' Add a radio button to a toolbar '''
button = RadioToolButton(group=group)
button.set_icon_name(icon_name)
if tooltip is not None:
button.set_tooltip(tooltip)
if cb_arg is None:
button.connect('clicked', callback)
else:
button.connect('clicked', callback, cb_arg)
if hasattr(toolbar, 'insert'): # the main toolbar
toolbar.insert(button, -1)
else: # or a secondary toolbar
toolbar.props.page.insert(button, -1)
button.show()
return button