# -*- coding: UTF-8 -*- # toolbars.py, see CalcActivity.py for info #import pygtk #pygtk.require('2.0') from gi.repository import Gtk from mathlib import MathLib from sugar3.graphics.palette import Palette from sugar3.graphics.menuitem import MenuItem from sugar3.graphics.toolbutton import ToolButton from sugar3.graphics.toggletoolbutton import ToggleToolButton import logging _logger = logging.getLogger('calc-activity') from gettext import gettext as _ def _icon_exists(name): if name == '': return False theme = Gtk.IconTheme.get_default() info = theme.lookup_icon(name, 0, 0) if info: return True return False class IconToolButton(ToolButton): def __init__(self, icon_name, text, cb, help_cb=None, alt_html=''): ToolButton.__init__(self) if _icon_exists(icon_name): #self.set_icon(icon_name) self.props.icon_name = icon_name else: if alt_html == '': alt_html = icon_name label = Gtk.Label() label.set_markup(alt_html) label.show() self.set_label_widget(label) self.create_palette(text, help_cb) self.connect('clicked', cb) def create_palette(self, text, help_cb): p = Palette(text) if help_cb is not None: item = MenuItem(_('Help'), 'action-help') item.connect('activate', help_cb) item.show() p.menu.append(item) self.set_palette(p) class IconToggleToolButton(ToggleToolButton): def __init__(self, items, cb, desc): ToggleToolButton.__init__(self) self.items = items if 'icon' in items[0] and _icon_exists(items[0]['icon']): #self.set_named_icon(items[0]['icon']) self.props.icon_name = items[0]['icon'] elif 'html' in items[0]: self.set_label(items[0]['html']) # self.set_tooltip(items[0][1]) self.set_tooltip(desc) self.selected = 0 self.connect('clicked', self.toggle_button) self.callback = cb def toggle_button(self, w): self.selected = (self.selected + 1) % len(self.items) but = self.items[self.selected] if 'icon' in but and _icon_exists(but['icon']): #self.set_named_icon(but['icon']) self.props.icon_name = but['icon'] elif 'html' in but: _logger.info('Setting html: %s', but['html']) self.set_label(but['html']) # self.set_tooltip(but[1]) if self.callback is not None: if 'html' in but: self.callback(but['html']) else: self.callback(but) class TextToggleToolButton(Gtk.ToggleToolButton): def __init__(self, items, cb, desc, index=False): Gtk.ToggleToolButton.__init__(self) self.items = items self.set_label(items[0]) self.selected = 0 self.connect('clicked', self.toggle_button) self.callback = cb self.index = index self.set_tooltip_text(desc) def toggle_button(self, w): self.selected = (self.selected + 1) % len(self.items) but = self.items[self.selected] self.set_label(but) if self.callback is not None: if self.index: self.callback(self.selected) else: self.callback(but) class LineSeparator(Gtk.SeparatorToolItem): def __init__(self): Gtk.SeparatorToolItem.__init__(self) self.set_draw(True) class EditToolbar(Gtk.Toolbar): def __init__(self, calc): Gtk.Toolbar.__init__(self) copy_tool = ToolButton('edit-copy') copy_tool.set_tooltip(_('Copy')) copy_tool.set_accelerator(_('c')) copy_tool.connect('clicked', lambda x: calc.text_copy()) self.insert(copy_tool, -1) menu_item = MenuItem(_('Cut')) try: menu_item.set_accelerator(_('x')) except AttributeError: pass menu_item.connect('activate', lambda x: calc.text_cut()) menu_item.show() copy_tool.get_palette().menu.append(menu_item) self.insert(IconToolButton('edit-paste', _('Paste'), lambda x: calc.text_paste(), alt_html='Paste'), -1) self.show_all() class AlgebraToolbar(Gtk.Toolbar): def __init__(self, calc): Gtk.Toolbar.__init__(self) self.insert(IconToolButton('algebra-square', _('Square'), lambda x: calc.button_pressed(calc.TYPE_OP_POST, '**2'), lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(square)'), alt_html='x2'), -1) self.insert(IconToolButton('algebra-sqrt', _('Square root'), lambda x: calc.button_pressed(calc.TYPE_FUNCTION, 'sqrt'), lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(sqrt)'), alt_html='√x'), -1) self.insert(IconToolButton('algebra-xinv', _('Inverse'), lambda x: calc.button_pressed(calc.TYPE_OP_POST, '**-1'), lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(inv)'), alt_html='x-1'), -1) self.insert(LineSeparator(), -1) self.insert(IconToolButton('algebra-exp', _('e to the power x'), lambda x: calc.button_pressed(calc.TYPE_FUNCTION, 'exp'), lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(exp)'), alt_html='ex'), -1) self.insert(IconToolButton('algebra-xpowy', _('x to the power y'), lambda x: calc.button_pressed(calc.TYPE_FUNCTION, 'pow'), lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(pow)'), alt_html='xy'), -1) self.insert(IconToolButton('algebra-ln', _('Natural logarithm'), lambda x: calc.button_pressed(calc.TYPE_FUNCTION, 'ln'), lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(ln)')), -1) self.insert(LineSeparator(), -1) self.insert(IconToolButton('algebra-fac', _('Factorial'), lambda x: calc.button_pressed(calc.TYPE_FUNCTION, 'fac'), lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(fac)')), -1) self.show_all() class TrigonometryToolbar(Gtk.Toolbar): def __init__(self, calc): Gtk.Toolbar.__init__(self) self.insert(IconToolButton('trigonometry-sin', _('Sine'), lambda x: calc.button_pressed(calc.TYPE_FUNCTION, 'sin'), lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(sin)')), -1) self.insert(IconToolButton('trigonometry-cos', _('Cosine'), lambda x: calc.button_pressed(calc.TYPE_FUNCTION, 'cos'), lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(cos)')), -1) self.insert(IconToolButton('trigonometry-tan', _('Tangent'), lambda x: calc.button_pressed(calc.TYPE_FUNCTION, 'tan'), lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(tan)')), -1) self.insert(LineSeparator(), -1) self.insert(IconToolButton('trigonometry-asin', _('Arc sine'), lambda x: calc.button_pressed(calc.TYPE_FUNCTION, 'asin'), lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(asin)')), -1) self.insert(IconToolButton('trigonometry-acos', _('Arc cosine'), lambda x: calc.button_pressed(calc.TYPE_FUNCTION, 'acos'), lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(acos)')), -1) self.insert(IconToolButton('trigonometry-atan', _('Arc tangent'), lambda x: calc.button_pressed(calc.TYPE_FUNCTION, 'atan'), lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(atan)')), -1) self.insert(LineSeparator(), -1) self.insert(IconToolButton('trigonometry-sinh', _('Hyperbolic sine'), lambda x: calc.button_pressed(calc.TYPE_FUNCTION, 'sinh'), lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(sinh)')), -1) self.insert(IconToolButton('trigonometry-cosh', _('Hyperbolic cosine'), lambda x: calc.button_pressed(calc.TYPE_FUNCTION, 'cosh'), lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(cosh)')), -1) self.insert(IconToolButton('trigonometry-tanh', _('Hyperbolic tangent'), lambda x: calc.button_pressed(calc.TYPE_FUNCTION, 'tanh'), lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(tanh)')), -1) self.show_all() class BooleanToolbar(Gtk.Toolbar): def __init__(self, calc): Gtk.Toolbar.__init__(self) self.insert(IconToolButton('boolean-and', _('Logical and'), lambda x: calc.button_pressed(calc.TYPE_OP_POST, '&'), lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(And)')), -1) self.insert(IconToolButton('boolean-or', _('Logical or'), lambda x: calc.button_pressed(calc.TYPE_OP_POST, '|'), lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(Or)')), -1) # self.insert(IconToolButton('boolean-xor', _('Logical xor'), # lambda x: calc.button_pressed(calc.TYPE_OP_POST, '^'), # lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(xor)')), -1) self.insert(LineSeparator(), -1) self.insert(IconToolButton('boolean-eq', _('Equals'), lambda x: calc.button_pressed(calc.TYPE_OP_POST, '==')), -1) self.insert(IconToolButton('boolean-neq', _('Not equals'), lambda x: calc.button_pressed(calc.TYPE_OP_POST, '!=')), -1) self.show_all() class MiscToolbar(Gtk.Toolbar): def __init__(self, calc, target_toolbar=None): Gtk.Toolbar.__init__(self) self.insert(IconToolButton('constants-pi', _('Pi'), lambda x: calc.button_pressed(calc.TYPE_TEXT, 'pi'), alt_html='π'), -1) self.insert(IconToolButton('constants-e', _('e'), lambda x: calc.button_pressed(calc.TYPE_TEXT, 'e')), -1) self.insert(IconToolButton('constants-eulersconstant', _('γ'), lambda x: calc.button_pressed(calc.TYPE_TEXT, '0.577215664901533')), -1) self.insert(IconToolButton('constants-goldenratio', _('φ'), lambda x: calc.button_pressed(calc.TYPE_TEXT, '1.618033988749895')), -1) if target_toolbar is None: target_toolbar = self target_toolbar.insert(LineSeparator(), -1) target_toolbar.insert(IconToolButton('plot', _('Plot'), lambda x: calc.button_pressed(calc.TYPE_FUNCTION, 'plot'), lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(plot)')), -1) target_toolbar.insert(LineSeparator(), -1) el = [ {'icon': 'format-deg', 'desc': _('Degrees'), 'html': 'deg'}, {'icon': 'format-rad', 'desc': _('Radians'), 'html': 'rad'}, ] target_toolbar.insert(IconToggleToolButton(el, lambda x: self.update_angle_type(x, calc), _('Degrees / Radians')), -1) self.update_angle_type('deg', calc) el = [ {'icon': 'format-sci', 'html': 'sci'}, {'icon': 'format-exp', 'html': 'exp'}, ] target_toolbar.insert(IconToggleToolButton(el, lambda x: self.update_format_type(x, calc), _('Exponent / Scientific notation')), -1) el = [ {'icon': 'digits-9', 'html': '9'}, {'icon': 'digits-12', 'html': '12'}, {'icon': 'digits-15', 'html': '15'}, {'icon': 'digits-6', 'html': '6'}, ] target_toolbar.insert(IconToggleToolButton(el, lambda x: self.update_digits(x, calc), _('Number of shown digits')), -1) el = [ {'icon': 'base-10', 'html': '10'}, {'icon': 'base-2', 'html': '2'}, {'icon': 'base-16', 'html': '16'}, {'icon': 'base-8', 'html': '8'} ] target_toolbar.insert(IconToggleToolButton(el, lambda x: self.update_int_base(x, calc), _('Integer formatting base')), -1) self.show_all() def update_angle_type(self, text, calc): var = calc.parser.get_var('angle_scaling') if var is None: _logger.warning('Variable angle_scaling not defined.') return if text == 'deg': var.value = MathLib.ANGLE_DEG elif text == 'rad': var.value = MathLib.ANGLE_RAD _logger.debug('Angle scaling: %s', var.value) def update_format_type(self, text, calc): if text == 'exp': calc.ml.set_format_type(MathLib.FORMAT_EXPONENT) elif text == 'sci': calc.ml.set_format_type(MathLib.FORMAT_SCIENTIFIC) _logger.debug('Format type: %s', calc.ml.format_type) def update_digits(self, text, calc): calc.ml.set_digit_limit(int(text)) _logger.debug('Digit limit: %s', calc.ml.digit_limit) def update_int_base(self, text, calc): calc.ml.set_integer_base(int(text)) _logger.debug('Integer base: %s', calc.ml.integer_base)