Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorReinier Heeres <reinier@heeres.eu>2009-01-10 10:48:04 (GMT)
committer Reinier Heeres <reinier@heeres.eu>2009-01-10 10:48:04 (GMT)
commitfd7466397a4b5c6c74357d199df0a34d5f014695 (patch)
tree0ede5a6d53e3949c1c6427781fde2a0db68e0bab
parentaad50487ee6a52a66b67078724cffbbb1aed19cf (diff)
Major calculate update.
Refactor result drawing code and add drawing of scientific notation Add selection of # of digit selection (+icons) Add switch between exponential/scientific notation
-rw-r--r--NEWS8
-rw-r--r--calculate.py275
-rw-r--r--icons/digits-12.svg11
-rw-r--r--icons/digits-15.svg11
-rw-r--r--icons/digits-6.svg11
-rw-r--r--icons/digits-9.svg11
-rw-r--r--icons/format-exp.svg11
-rw-r--r--icons/format-sci.svg11
-rw-r--r--layout.py27
-rw-r--r--toolbars.py64
10 files changed, 305 insertions, 135 deletions
diff --git a/NEWS b/NEWS
index 08eedfd..488704d 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,11 @@
+* Support 'real' scientific notation (#4250)
+* Add switching between exponential/scientific notation
+* Allow changing of number of displayed digits
+* Change cursor on equations to Hand (#6612)
+* Fix fall-through of unhandled CTRL keys (eg CTRL+Q)
+* Add recursion detection
+* Fixed error-handling bug
+
26
* Refactored equation drawing code
diff --git a/calculate.py b/calculate.py
index 472c52b..d91eb7f 100644
--- a/calculate.py
+++ b/calculate.py
@@ -42,12 +42,35 @@ from sugar.graphics.xocolor import XoColor
from shareable_activity import ShareableActivity
from layout import CalcLayout
from mathlib import MathLib
-from astparser import AstParser, ParseError
+from astparser import AstParser, ParserError, RuntimeError
from svgimage import SVGImage
from decimal import Decimal
from rational import Rational
+def findchar(text, chars, ofs=0):
+ '''
+ Find a character in set <chars> starting from offset ofs.
+ Everything between brackets '()' is ignored.
+ '''
+
+ level = 0
+ for i in range(ofs, len(text)):
+ if text[i] == '(':
+ level += 1
+ elif text[i] == ')':
+ level -= 1
+ elif text[i] in chars and level == 0:
+ return i
+
+ return -1
+
+def _textview_realize_cb(widget):
+ '''Change textview properties once window is created.'''
+ win = widget.get_window(gtk.TEXT_WINDOW_TEXT)
+ win.set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND1))
+ return False
+
class Equation:
def __init__(self, label=None, eqn=None, res=None, col=None, owner=None, \
eqnstr=None, ml=None):
@@ -98,47 +121,112 @@ class Equation:
self.set(l[0], l[1], l[2], XoColor(color_string=l[3]), l[4])
- def format_history_buf(self, buf):
- """Apply proper formatting to a gtk.TextBuffer for the history"""
-
- iter_start = buf.get_start_iter()
- iter_colon = buf.get_start_iter()
- iter_end = buf.get_end_iter()
- iter_middle = buf.get_iter_at_line(1)
- try:
- pos = buf.get_text(iter_start, iter_end).index(':')
- iter_colon.forward_chars(pos)
- except:
- buf.apply_tag(buf.create_tag(font=CalcLayout.FONT_SMALL),
- iter_start, iter_middle)
+ def determine_font_size(self, *tags):
+ size = 0
+ for tag in tags:
+ try:
+ size = max(size, tag.get_property('size'))
+ except:
+ pass
+ return size
+
+ def append_with_superscript_tags(self, buf, text, *tags):
+ '''Add a text to a gtk.TextBuffer with superscript tags.'''
+
+ fontsize = self.determine_font_size(*tags)
+ _logger.debug('font-size: %d', fontsize)
+ tagsuper = buf.create_tag(rise=fontsize/2)
+
+ ofs = 0
+ while ofs <= len(text) and text.find('**', ofs) != -1:
+ nextofs = text.find('**', ofs)
+ buf.insert_with_tags(buf.get_end_iter(), text[ofs:nextofs], *tags)
+ nextofs2 = findchar(text, ['+','-', '*', '/'], nextofs + 2)
+ if nextofs2 == -1:
+ nextofs2 = len(text)
+ buf.insert_with_tags(buf.get_end_iter(), text[nextofs+2:nextofs2],
+ tagsuper, *tags)
+ ofs = nextofs2
+
+ if ofs < len(text):
+ buf.insert_with_tags(buf.get_end_iter(), text[ofs:], *tags)
+
+ def create_lasteq_textbuf(self):
+ '''
+ Return a gtk.TextBuffer properly formatted for last equation
+ gtk.TextView.
+ '''
+
+ is_error = isinstance(self.result, ParserError)
+ buf = gtk.TextBuffer()
+ tagsmallnarrow = buf.create_tag(font=CalcLayout.FONT_SMALL_NARROW)
+ tagbignarrow = buf.create_tag(font=CalcLayout.FONT_BIG_NARROW)
+ tagbigger = buf.create_tag(font=CalcLayout.FONT_BIGGER)
+ tagjustright = buf.create_tag(justification=gtk.JUSTIFY_RIGHT)
+ tagred = buf.create_tag(foreground='#FF0000')
+
+ # Add label and equation
+ if len(self.label) > 0:
+ labelstr = '%s:' % self.label
+ buf.insert_with_tags(buf.get_end_iter(), labelstr, tagbignarrow)
+ eqnoffset = buf.get_end_iter().get_offset()
+ eqnstr = '%s\n' % str(self.equation)
+ if is_error:
+ buf.insert_with_tags(buf.get_end_iter(), eqnstr, tagbignarrow)
else:
- buf.apply_tag(buf.create_tag(font=CalcLayout.FONT_SMALL_NARROW),
- iter_start, iter_colon)
- buf.apply_tag(buf.create_tag(font=CalcLayout.FONT_SMALL),
- iter_colon, iter_middle)
+ self.append_with_superscript_tags(buf, eqnstr, tagbignarrow)
+
+ # Add result
+ if type(self.result) is types.StringType:
+ resstr = str(self.result)
+ buf.insert_with_tags(buf.get_end_iter(), resstr,
+ tagsmallnarrow, tagjustright)
+ elif is_error:
+ resstr = str(self.result)
+ buf.insert_with_tags(buf.get_end_iter(), resstr, tagbigger)
+ range = self.result.get_range()
+ eqnstart = buf.get_iter_at_offset(eqnoffset + range[0])
+ eqnend = buf.get_iter_at_offset(eqnoffset + range[1])
+ buf.apply_tag(tagred, eqnstart, eqnend)
+ elif not isinstance(self.result, SVGImage):
+ resstr = self.ml.format_number(self.result)
+ self.append_with_superscript_tags(buf, resstr, tagbigger,
+ tagjustright)
+
+ return buf
+
+ def create_history_object(self):
+ """
+ Create a history object for this equation.
+ In case of an SVG result this will be the image, otherwise it will
+ return a properly formatted gtk.TextView.
+ """
- buf.apply_tag(buf.create_tag(font=CalcLayout.FONT_BIG,
- justification=gtk.JUSTIFY_RIGHT), iter_middle, iter_end)
- col = self.color.get_fill_color()
- buf.apply_tag(buf.create_tag(foreground=col), iter_start, iter_end)
+ if isinstance(self.result, SVGImage):
+ return self.result.get_image()
- def create_textview(self):
- """Create a gtk.TextView object for this equation."""
+ w = gtk.TextView()
+ w.set_wrap_mode(gtk.WRAP_WORD)
+ w.connect('realize', _textview_realize_cb)
+ buf = w.get_buffer()
+
+ tagsmall = buf.create_tag(font=CalcLayout.FONT_SMALL)
+ tagsmallnarrow = buf.create_tag(font=CalcLayout.FONT_SMALL_NARROW)
+ tagbig = buf.create_tag(font=CalcLayout.FONT_BIG,
+ justification=gtk.JUSTIFY_RIGHT)
+ col = self.color.get_fill_color()
+ tagcolor = buf.create_tag(foreground=col)
- if isinstance(self.result, SVGImage):
- w = self.result.get_image()
+ # Add label, equation and result
+ if len(self.label) > 0:
+ labelstr = '%s:' % self.label
+ buf.insert_with_tags(buf.get_end_iter(), labelstr, tagsmallnarrow)
+ eqnstr = '%s\n' % str(self.equation)
+ self.append_with_superscript_tags(buf, eqnstr, tagsmall)
+ resstr = self.ml.format_number(self.result)
+ self.append_with_superscript_tags(buf, resstr, tagbig)
- else:
- text = ""
- if len(self.label) > 0:
- text += str(self.label) + ": "
- r = self.ml.format_number(self.result)
- text += str(self.equation) + "\n=" + r
- w = gtk.TextView()
- w.set_wrap_mode(gtk.WRAP_WORD)
- b = w.get_buffer()
- b.set_text(text)
- self.format_history_buf(b)
+ buf.apply_tag(tagcolor, buf.get_start_iter(), buf.get_end_iter())
return w
@@ -230,7 +318,6 @@ class Calculate(ShareableActivity):
self.layout = CalcLayout(self)
self.label_entry = self.layout.label_entry
self.text_entry = self.layout.text_entry
- self.last_eq = self.layout.last_eq.get_buffer()
self.last_eq_sig = None
self.last_eqn_textview = None
@@ -261,68 +348,19 @@ class Calculate(ShareableActivity):
self.button_pressed(self.TYPE_TEXT, text)
return True
- def format_last_eq_buf(self, buf, res, offset=0):
- """
- Format the 'last equation' gtk.TextBuffer properly.
-
- Input:
- buf: the gtk.TextBuffer
- res: the result, ParseError object in case of error
- offset: offset where the equation starts in the TextBuffer
- """
-
- eq_start = buf.get_start_iter()
- eq_middle = buf.get_iter_at_line(1)
- eq_end = buf.get_end_iter()
- buf.apply_tag(buf.create_tag(font=CalcLayout.FONT_BIG_NARROW),
- eq_start, eq_middle)
-
-# String results should be a little smaller
- if type(res) == types.StringType or res is None:
- buf.apply_tag(buf.create_tag(font=CalcLayout.FONT_BIG_NARROW,
- justification=gtk.JUSTIFY_RIGHT), eq_middle, eq_end)
- else:
- buf.apply_tag(buf.create_tag(font=CalcLayout.FONT_BIGGER,
- justification=gtk.JUSTIFY_RIGHT), eq_middle, eq_end)
-
-# Format error
- if isinstance(res, ParseError):
- range = res.get_range()
- eq_start.forward_chars(range[0] + offset)
- end = self.last_eq.get_start_iter()
- end.forward_chars(range[1] + offset)
- self.last_eq.apply_tag(self.last_eq.create_tag(foreground='#FF0000'),
- eq_start, end)
- self.last_eq.apply_tag(self.last_eq.create_tag(foreground='#FF0000'),
- eq_middle, eq_end)
-
def set_last_equation(self, eqn):
- """Fill the 'last equation' TextView"""
-
- if len(eqn.label) > 0:
- text = eqn.label + ': ' + eqn.equation
- offset = len(eqn.label) + 2
- else:
- text = eqn.equation
- offset = 0
+ """Set the 'last equation' TextView"""
if self.last_eq_sig is not None:
self.layout.last_eq.disconnect(self.last_eq_sig)
self.last_eq_sig = None
- if isinstance(eqn.result, ParseError):
- text += "\n" + str(eqn.result)
- else:
- if isinstance(eqn.result, SVGImage):
- pass
- else:
- text += '\n= ' + self.ml.format_number(eqn.result)
-
- self.last_eq_sig = self.layout.last_eq.connect('button-press-event', \
- lambda a1, a2, e: self.equation_pressed_cb(e), eqn)
+ if not isinstance(eqn.result, ParserError):
+ self.last_eq_sig = self.layout.last_eq.connect(
+ 'button-press-event',
+ lambda a1, a2, e: self.equation_pressed_cb(e), eqn)
- self.last_eq.set_text(text)
- self.format_last_eq_buf(self.last_eq, eqn.result, offset)
+ self.layout.last_eq.set_buffer(eqn.create_lasteq_textbuf())
def set_error_equation(self, eqn):
"""Set equation with error markers. Since set_last_equation implements
@@ -362,7 +400,7 @@ class Calculate(ShareableActivity):
self.last_eqn_textview = None
own = (eq.owner == self.get_owner_id())
- w = eq.create_textview()
+ w = eq.create_history_object()
w.connect('button-press-event', lambda w, e: self.equation_pressed_cb(eq))
if drawlasteq:
self.set_last_equation(eq)
@@ -384,6 +422,7 @@ class Calculate(ShareableActivity):
tree = self.parser.parse(eq.equation)
self.parser.set_var(eq.label, tree)
+ # FIXME: to be implemented
def process_async(self, eqn):
"""Parse and process an equation asynchronously."""
@@ -396,7 +435,7 @@ class Calculate(ShareableActivity):
try:
tree = self.parser.parse(s)
res = self.parser.evaluate(tree)
- except ParseError, e:
+ except ParserError, e:
res = e
self.showing_error = True
@@ -405,10 +444,17 @@ class Calculate(ShareableActivity):
_logger.debug('Result: %r', res)
+ # Check whether assigning this label would cause recursion
+ if not isinstance(res, ParserError) and len(label) > 0:
+ lastpos = self.parser.get_var_used_ofs(label)
+ if lastpos is not None:
+ res = RuntimeError(_('Can not assign label: will cause recursion'),
+ lastpos)
+
# If parsing went ok, see if we have to replace the previous answer
# to get a (more) exact result
- if self.ans_inserted and not isinstance(res, ParseError) and \
- not isinstance(res, SVGImage):
+ if self.ans_inserted and not isinstance(res, ParserError) \
+ and not isinstance(res, SVGImage):
ansvar = self.format_insert_ans()
pos = s.find(ansvar)
if len(ansvar) > 6 and pos != -1:
@@ -419,14 +465,17 @@ class Calculate(ShareableActivity):
eqn = Equation(label, s, res, self.color, self.get_owner_id(), ml=self.ml)
- if isinstance(res, ParseError):
+ if isinstance(res, ParserError):
self.set_error_equation(eqn)
else:
self.add_equation(eqn, drawlasteq=True, tree=tree)
self.send_message("add_eq", value=str(eqn))
self.parser.set_var('Ans', eqn.result)
- self.parser.set_var('LastEqn', tree)
+
+ # Setting LastEqn to the parse tree would certainly be faster,
+ # however, it introduces recursion problems
+ self.parser.set_var('LastEqn', eqn.result)
self.showing_error = False
self.ans_inserted = False
@@ -435,16 +484,6 @@ class Calculate(ShareableActivity):
return res is not None
- def format_var_buf(self, buf):
- """Apply formatting to a gtk.TextBuffer to show a variable"""
-
- iter_start = buf.get_start_iter()
- iter_end = buf.get_end_iter()
- buf.apply_tag(buf.create_tag(font=CalcLayout.FONT_SMALL_NARROW),
- iter_start, iter_end)
- col = self.color.get_fill_color()
- buf.apply_tag(buf.create_tag(foreground=col), iter_start, iter_end)
-
def create_var_textview(self, name, value):
"""Create a gtk.TextView for a variable"""
@@ -452,11 +491,16 @@ class Calculate(ShareableActivity):
if name in reserved:
return None
w = gtk.TextView()
+ w.connect('realize', _textview_realize_cb)
w.set_left_margin(5)
w.set_right_margin(5)
- b = w.get_buffer()
- b.set_text(name + ":\t" + str(value))
- self.format_var_buf(b)
+ buf = w.get_buffer()
+
+ col = self.color.get_fill_color()
+ tag = buf.create_tag(font=CalcLayout.FONT_SMALL_NARROW,
+ foreground=col)
+ text = '%s:\t%s' % (name,str(value))
+ buf.insert_with_tags(buf.get_end_iter(), text, tag)
return w
@@ -663,9 +707,10 @@ class Calculate(ShareableActivity):
key = 'multiply'
_logger.debug('Key: %s (%r, %r)', key, event.keyval, event.hardware_keycode)
- if (event.state & gtk.gdk.CONTROL_MASK) and self.CTRL_KEYMAP.has_key(key):
- f = self.CTRL_KEYMAP[key]
- return f(self)
+ if event.state & gtk.gdk.CONTROL_MASK:
+ if self.CTRL_KEYMAP.has_key(key):
+ f = self.CTRL_KEYMAP[key]
+ return f(self)
elif (event.state & gtk.gdk.SHIFT_MASK) and self.SHIFT_KEYMAP.has_key(key):
f = self.SHIFT_KEYMAP[key]
return f(self)
diff --git a/icons/digits-12.svg b/icons/digits-12.svg
new file mode 100644
index 0000000..87e2854
--- /dev/null
+++ b/icons/digits-12.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+ <!ENTITY fill_color "#FFFFFF">
+]><svg enable-background="new 0 0 55 55" height="55px" version="1.1" viewBox="0 0 55 55" width="55px" x="0px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" y="0px"><g display="block" id="stock-xo_1_">
+ <defs>
+ <mask id="Mask" maskUnits="userSpaceOnUse" x="0" y="0" width="55" height="55">
+ <path d="M 3 3 L 53 3 L 53 53 L 3 53 z" stroke-width="3.5" fill="white" stroke="white"/>
+ <text x="2" y="41" font-size="36" font-family="Bitstream Vera Sans" font-weight="bold" fill="black" stroke="none">12</text>
+ </mask>
+ </defs>
+ <path d="M 3 12 Q 3 3 12 3 L 43 3 Q 53 3 53 12 L 53 43 Q 53 53 43 53 L 12 53 Q 3 53 3 43 z" fill="&fill_color;" stroke="&fill_color;" stroke-width="3.5" mask="url(#Mask)"/>
+</g></svg>
diff --git a/icons/digits-15.svg b/icons/digits-15.svg
new file mode 100644
index 0000000..3951c41
--- /dev/null
+++ b/icons/digits-15.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+ <!ENTITY fill_color "#FFFFFF">
+]><svg enable-background="new 0 0 55 55" height="55px" version="1.1" viewBox="0 0 55 55" width="55px" x="0px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" y="0px"><g display="block" id="stock-xo_1_">
+ <defs>
+ <mask id="Mask" maskUnits="userSpaceOnUse" x="0" y="0" width="55" height="55">
+ <path d="M 3 3 L 53 3 L 53 53 L 3 53 z" stroke-width="3.5" fill="white" stroke="white"/>
+ <text x="2" y="41" font-size="36" font-family="Bitstream Vera Sans" font-weight="bold" fill="black" stroke="none">15</text>
+ </mask>
+ </defs>
+ <path d="M 3 12 Q 3 3 12 3 L 43 3 Q 53 3 53 12 L 53 43 Q 53 53 43 53 L 12 53 Q 3 53 3 43 z" fill="&fill_color;" stroke="&fill_color;" stroke-width="3.5" mask="url(#Mask)"/>
+</g></svg>
diff --git a/icons/digits-6.svg b/icons/digits-6.svg
new file mode 100644
index 0000000..1d892fa
--- /dev/null
+++ b/icons/digits-6.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+ <!ENTITY fill_color "#FFFFFF">
+]><svg enable-background="new 0 0 55 55" height="55px" version="1.1" viewBox="0 0 55 55" width="55px" x="0px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" y="0px"><g display="block" id="stock-xo_1_">
+ <defs>
+ <mask id="Mask" maskUnits="userSpaceOnUse" x="0" y="0" width="55" height="55">
+ <path d="M 3 3 L 53 3 L 53 53 L 3 53 z" stroke-width="3.5" fill="white" stroke="white"/>
+ <text x="15" y="41" font-size="36" font-family="Bitstream Vera Sans" font-weight="bold" fill="black" stroke="none">6</text>
+ </mask>
+ </defs>
+ <path d="M 3 12 Q 3 3 12 3 L 43 3 Q 53 3 53 12 L 53 43 Q 53 53 43 53 L 12 53 Q 3 53 3 43 z" fill="&fill_color;" stroke="&fill_color;" stroke-width="3.5" mask="url(#Mask)"/>
+</g></svg>
diff --git a/icons/digits-9.svg b/icons/digits-9.svg
new file mode 100644
index 0000000..2a7c2b7
--- /dev/null
+++ b/icons/digits-9.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+ <!ENTITY fill_color "#FFFFFF">
+]><svg enable-background="new 0 0 55 55" height="55px" version="1.1" viewBox="0 0 55 55" width="55px" x="0px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" y="0px"><g display="block" id="stock-xo_1_">
+ <defs>
+ <mask id="Mask" maskUnits="userSpaceOnUse" x="0" y="0" width="55" height="55">
+ <path d="M 3 3 L 53 3 L 53 53 L 3 53 z" stroke-width="3.5" fill="white" stroke="white"/>
+ <text x="15" y="41" font-size="36" font-family="Bitstream Vera Sans" font-weight="bold" fill="black" stroke="none">9</text>
+ </mask>
+ </defs>
+ <path d="M 3 12 Q 3 3 12 3 L 43 3 Q 53 3 53 12 L 53 43 Q 53 53 43 53 L 12 53 Q 3 53 3 43 z" fill="&fill_color;" stroke="&fill_color;" stroke-width="3.5" mask="url(#Mask)"/>
+</g></svg>
diff --git a/icons/format-exp.svg b/icons/format-exp.svg
new file mode 100644
index 0000000..24d3d63
--- /dev/null
+++ b/icons/format-exp.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+ <!ENTITY fill_color "#FFFFFF">
+]><svg enable-background="new 0 0 55 55" height="55px" version="1.1" viewBox="0 0 55 55" width="55px" x="0px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" y="0px"><g display="block" id="stock-xo_1_">
+ <defs>
+ <mask id="Mask" maskUnits="userSpaceOnUse" x="0" y="0" width="55" height="55">
+ <path d="M 3 3 L 53 3 L 53 53 L 3 53 z" stroke-width="3.5" fill="white" stroke="white"/>
+ <text x="2" y="35" font-size="25" font-family="Bitstream Vera Sans" font-weight="bold" fill="black" stroke="none">exp</text>
+ </mask>
+ </defs>
+ <path d="M 3 12 Q 3 3 12 3 L 43 3 Q 53 3 53 12 L 53 43 Q 53 53 43 53 L 12 53 Q 3 53 3 43 z" fill="&fill_color;" stroke="&fill_color;" stroke-width="3.5" mask="url(#Mask)"/>
+</g></svg>
diff --git a/icons/format-sci.svg b/icons/format-sci.svg
new file mode 100644
index 0000000..6670b83
--- /dev/null
+++ b/icons/format-sci.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+ <!ENTITY fill_color "#FFFFFF">
+]><svg enable-background="new 0 0 55 55" height="55px" version="1.1" viewBox="0 0 55 55" width="55px" x="0px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" y="0px"><g display="block" id="stock-xo_1_">
+ <defs>
+ <mask id="Mask" maskUnits="userSpaceOnUse" x="0" y="0" width="55" height="55">
+ <path d="M 3 3 L 53 3 L 53 53 L 3 53 z" stroke-width="3.5" fill="white" stroke="white"/>
+ <text x="9" y="35" font-size="25" font-family="Bitstream Vera Sans" font-weight="bold" fill="black" stroke="none">sci</text>
+ </mask>
+ </defs>
+ <path d="M 3 12 Q 3 3 12 3 L 43 3 Q 53 3 53 12 L 53 43 Q 53 53 43 53 L 12 53 Q 3 53 3 43 z" fill="&fill_color;" stroke="&fill_color;" stroke-width="3.5" mask="url(#Mask)"/>
+</g></svg>
diff --git a/layout.py b/layout.py
index 24166ea..b29ceaf 100644
--- a/layout.py
+++ b/layout.py
@@ -11,11 +11,14 @@ from toolbars import *
class CalcLayout:
- FONT_SMALL = "sans 10"
- FONT_SMALL_NARROW = "sans italic 10"
- FONT_BIG = "sans bold 14"
+ FONT_SMALL_POINTS = 10
+ FONT_SMALL = "sans %d" % FONT_SMALL_POINTS
+ FONT_SMALL_NARROW = "sans italic %d" % FONT_SMALL_POINTS
+ FONT_BIG_POINTS = 14
+ FONT_BIG = "sans bold %d" % FONT_BIG_POINTS
FONT_BIG_NARROW = "sans italic 14"
- FONT_BIGGER = "sans bold 18"
+ FONT_BIGGER_POINTS = 18
+ FONT_BIGGER = "sans bold %d" % FONT_BIGGER_POINTS
def __init__(self, parent):
self._parent = parent
@@ -132,10 +135,14 @@ class CalcLayout:
hc2 = gtk.HBox()
self.minebut = TextToggleToolButton(
[_('All equations'), _('My equations')],
- self._all_equations_toggle_cb, index=True)
+ self._all_equations_toggle_cb,
+ _('Change view between own and all eqauations'),
+ index=True)
self.varbut = TextToggleToolButton(
[_('Show history'), _('Show variables')],
- self._history_toggle_cb, index=True)
+ self._history_toggle_cb,
+ _('Change view between history and variables'),
+ index=True)
hc2.add(self.minebut)
hc2.add(self.varbut)
self.grid.attach(hc2, 6, 11, 0, 1)
@@ -144,6 +151,7 @@ class CalcLayout:
self.last_eq = gtk.TextView()
self.last_eq.set_editable(False)
self.last_eq.set_wrap_mode(gtk.WRAP_WORD)
+ self.last_eq.connect('realize', self._textview_realize_cb)
self.grid.attach(self.last_eq, 6, 11, 1, 5)
# Right part: history
@@ -264,3 +272,10 @@ class CalcLayout:
self.show_history()
else:
self.show_variables()
+
+ def _textview_realize_cb(self, widget):
+ '''Change textview properties once window is created.'''
+ win = widget.get_window(gtk.TEXT_WINDOW_TEXT)
+ win.set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND1))
+ return False
+
diff --git a/toolbars.py b/toolbars.py
index 9391ff3..478b681 100644
--- a/toolbars.py
+++ b/toolbars.py
@@ -62,9 +62,9 @@ class IconToggleToolButton(ToggleToolButton):
def __init__(self, items, cb, desc):
ToggleToolButton.__init__(self)
self.items = items
- if _icon_exists(items[0]['icon']):
+ if 'icon' in items[0] and _icon_exists(items[0]['icon']):
self.set_named_icon(items[0]['icon'])
- else:
+ elif 'html' in items[0]:
self.set_label(items[0]['html'])
# self.set_tooltip(items[0][1])
self.set_tooltip(desc)
@@ -75,16 +75,20 @@ class IconToggleToolButton(ToggleToolButton):
def toggle_button(self, w):
self.selected = (self.selected + 1) % len(self.items)
but = self.items[self.selected]
- if _icon_exists(but['icon']):
+ if 'icon' in but and _icon_exists(but['icon']):
self.set_named_icon(but['icon'])
- else:
+ 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:
- self.callback(but)
+ if 'html' in but:
+ self.callback(but['html'])
+ else:
+ self.callback(but)
class TextToggleToolButton(gtk.ToggleToolButton):
- def __init__(self, items, cb, index=False):
+ def __init__(self, items, cb, desc, index=False):
gtk.ToggleToolButton.__init__(self)
self.items = items
self.set_label(items[0])
@@ -92,6 +96,7 @@ class TextToggleToolButton(gtk.ToggleToolButton):
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)
@@ -129,7 +134,7 @@ class AlgebraToolbar(gtk.Toolbar):
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_OP_POST, '**2'),
lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(square)'),
alt_html='x<sup>2</sup>'), -1)
@@ -139,7 +144,7 @@ class AlgebraToolbar(gtk.Toolbar):
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_OP_POST, '**-1'),
lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(inv)'),
alt_html='x<sup>-1</sup>'), -1)
@@ -246,9 +251,15 @@ class MiscToolbar(gtk.Toolbar):
self.insert(LineSeparator(), -1)
+ self.insert(IconToolButton('plot', _('Plot'),
+ lambda x: calc.button_pressed(calc.TYPE_FUNCTION, 'plot'),
+ lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(plot)')), -1)
+
+ self.insert(LineSeparator(), -1)
+
el = [
- {'icon': 'format-deg', 'desc': _('Degrees'), 'html': 'Deg'},
- {'icon': 'format-rad', 'desc': _('Radians'), 'html': 'Rad'},
+ {'icon': 'format-deg', 'desc': _('Degrees'), 'html': 'deg'},
+ {'icon': 'format-rad', 'desc': _('Radians'), 'html': 'rad'},
]
self.insert(IconToggleToolButton(el,
lambda x: self.update_angle_type(x, calc),
@@ -256,14 +267,39 @@ class MiscToolbar(gtk.Toolbar):
self.insert(LineSeparator(), -1)
- self.insert(IconToolButton('plot', _('Plot'),
- lambda x: calc.button_pressed(calc.TYPE_FUNCTION, 'plot'),
- lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(plot)')), -1)
+ el = [
+ {'icon': 'format-sci', 'html': 'sci'},
+ {'icon': 'format-exp', 'html': 'exp'},
+ ]
+ self.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'},
+ ]
+ self.insert(IconToggleToolButton(el,
+ lambda x: self.update_digits(x, calc),
+ _('Number of shown digits')), -1)
def update_angle_type(self, text, calc):
if text == 'deg':
calc.ml.set_angle_type(MathLib.ANGLE_DEG)
elif text == 'rad':
calc.ml.set_angle_type(MathLib.ANGLE_RAD)
- _logger.debug('Angle type: %s', self.ml.angle_scaling)
+ _logger.debug('Angle type: %s', calc.ml.angle_scaling)
+
+ def update_format_type(self, text, calc):
+ if text == 'exp':
+ calc.ml.set_format_type(MathLib.FORMAT_EXPONENT)
+ elif text == 'sci':
+ calc.ml.set_angle_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)