1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
"""Module for mouse function input."""
import gtk
from .display import PuzzleDisplay
from .palette import PuzzlePalette
from .nodes import Node
_FILE_VERSION = 1
class PuzzleInput(gtk.VBox):
"""PuzzleInput is a control that uses mouse input to create functions."""
CLASS = "puzzle"
def __init__(self, app, rootnode=None):
"""Creates input (and display) of tree.
We'd like to support multiple trees for click-and-drag,
but for now, just one tree is made at a time.
"""
gtk.VBox.__init__(self)
self.app = app
# create box to hold display and undo button
displaybox = gtk.HBox()
self.pack_start(displaybox)
# create display for drawing function tree
displayscroll = gtk.ScrolledWindow()
displayscroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_NEVER)
displayview = gtk.Viewport()
self._display = PuzzleDisplay(rootnode)
displayview.add(self._display)
displayscroll.add(displayview)
displaybox.pack_start(displayscroll)
# undo button (TODO: this isn't really undo)
undoimage = gtk.Image()
undoimage.set_from_stock(gtk.STOCK_UNDO, gtk.ICON_SIZE_BUTTON)
undobutton = gtk.Button()
undobutton.add(undoimage)
undobutton.show_all()
displaybox.pack_start(undobutton, expand=False)
# connect undo event (should show palette and undo)
undobutton.connect("clicked", self.on_undo)
# create buttons for adding nodes
palette = PuzzlePalette(app, self._display)
self.pack_start(palette)
self._palette = palette
# hide palette if it cannot be used
self.show_all()
if (self._display.rootnode is not None and
self._display.nextnode is None):
palette.hide()
@staticmethod
def load(app, settings):
"""Create new input from dictionary state."""
if settings["version"] > _FILE_VERSION:
return PuzzleInput()
return PuzzleInput(app, Node.load(settings["settings"]))
def save(self):
"""Create a dictionary to save current state."""
nodesettings = None
if self._display.rootnode is not None:
nodesettings = self._display.rootnode.save()
settings = {
"version": _FILE_VERSION,
"settings": nodesettings
}
return settings
def on_undo(self, widget, data=None):
"""Undoes the previous action (removes bottom-right node)."""
removednode = self._display.undo()
self._palette.show_all()
# register action for undo/redo
def action():
self._display.undo()
self._palette.show_all()
def inverse():
self._display.addnode(removednode)
if self._display.nextnode is None:
self._palette.hide()
self.app.register_action(action, inverse)
def get_model(self):
"""Returns callable model from the tree."""
return self._display.get_model()
def get_equation_string(self):
"""Returns a string representing the current equation."""
return Node.get_equation_string(self._display.rootnode, "x")
|