diff options
Diffstat (limited to 'plotter/view/__init__.py')
-rwxr-xr-x | plotter/view/__init__.py | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/plotter/view/__init__.py b/plotter/view/__init__.py new file mode 100755 index 0000000..2bed743 --- /dev/null +++ b/plotter/view/__init__.py @@ -0,0 +1,243 @@ +"""Module for code-defined view objects. + +WARNING: do NOT put business logic in here. +Classes needing logic should use corresponding data models via +get_model(), load_model() methods. +""" + +import gtk +from gettext import gettext as _ + +from .equation import EquationInput as _EquationInput +from .puzzletree import PuzzleInput as _PuzzleInput + +# just in case we break backward compatibility +_FILE_VERSION = 1 +_EQUATION_VERSION = 1 + + +class EquationList(gtk.HBox): + """A list of equations.""" + + def __init__(self, app): + """Creates it...""" + gtk.HBox.__init__(self) + + # save application instance for undo/redo + self.app = app + + # create box for equation inputs + self.vbox = gtk.VBox() + self.vbox.show() + self.pack_start(self.vbox) + + # create add button for multiple equations + imagevbox = gtk.VBox() + addimage = gtk.Image() + addimage.set_from_stock(gtk.STOCK_ADD, gtk.ICON_SIZE_BUTTON) + addbutton = gtk.Button() + addbutton.add(addimage) + addbutton.show() + imagevbox.pack_end(addbutton, expand=False, fill=False) + imagevbox.show() + self.pack_start(imagevbox, expand=False) + addbutton.connect("clicked", self._on_add, None) + + # created default equation input + self._equations = [] + self._add_equation(_PuzzleInput(app)) + + + def save(self): + """Returns dictionary to be used in saving JSON.""" + + # create list of equations + equations_settings = [] + for equation in self._equations: + equations_settings.append(self._saveequation(equation)) + + settings = { + "version": _FILE_VERSION, + "equations": equations_settings + } + + return settings + + + def _saveequation(self, equation): + """Creates dictionary to save state of an equation.""" + + return { + "version": _EQUATION_VERSION, + "class": equation.CLASS, + "settings": equation.save() + } + + + def load(self, settings): + """Updates view with equations loaded from settings.""" + + if settings["version"] > _FILE_VERSION: + return + + # remove all existing equations + self.clear() + + # create new equations from settings + for equation in settings["equations"]: + self._loadequation(equation) + + + def _loadequation(self, equation): + """Loads an equation from saved state.""" + + if equation["version"] > _EQUATION_VERSION: + return + + # load input view from specified class + loaded = _VIEW_CLASSES[equation["class"]].load( + self.app, equation["settings"]) + loaded_input = self._add_equation(loaded) + return (loaded, loaded_input) + + + def get_model(self): + """Returns a list of equations.""" + + equations = [] + for equation in self._equations: + equations.append(equation.get_model()) + return equations + + + def _register_addremove(self, equation, equation_input, isadding=False): + """Register an add/remove equation action.""" + + # create actions (which preserve equation order) + i = self._equations.index(equation) + def remove(): + self._remove_equation(equation, equation_input) + def add(): + self._insert_equation_input(i, equation, equation_input) + + # register the action (inverse switched for adding vs removing) + action = remove + inverse = add + if isadding: + action = add + inverse = remove + self.app.register_action(action, inverse) + + + def _on_add(self, widget, data=None): + """Event to add a new equation input.""" + + # add a new equation + equation = _PuzzleInput(self.app) + equation_input = self._add_equation(equation) + + # register the action for undo/redo + self._register_addremove(equation, equation_input, isadding=True) + + + def _on_remove(self, widget, equation, equation_input): + """Event to remove an equation.""" + self._register_addremove(equation, equation_input, isadding=False) + self._remove_equation(equation, equation_input) + + + def _remove_equation(self, equation, equation_input): + """Removes an equation from the list.""" + self._equations.remove(equation) + self.vbox.remove(equation_input) + + + def _add_equation_input(self, equation, equation_input): + """Adds an equation to the end of the list.""" + self._equations.append(equation) + self.vbox.pack_start(equation_input, expand=False) + + + def _insert_equation_input(self, i, equation, equation_input): + """Inserts an equation to the list at position i.""" + self._equations.insert(i, equation) + self.vbox.pack_start(equation_input, expand=False) + self.vbox.reorder_child(equation_input, i) + + + def _convert_equation(self, equation, equation_input): + """Converts an equation into a Python input.""" + + # create new control with python equation text + i = self._equations.index(equation) + equationstring = equation.get_equation_string() + pythonequation = _EquationInput(self.app, equationstring) + pythonequation_input = self._create_equation(pythonequation) + + # register the action (for undo/redo) + def inverse(): + self._remove_equation(pythonequation, pythonequation_input) + self._insert_equation_input(i, equation, equation_input) + def action(): + self._remove_equation(equation, equation_input) + self._insert_equation_input(i, pythonequation, pythonequation_input) + self.app.register_action(action, inverse) + action() + + + def _create_equation(self, equation): + """Creates input for equation without adding it to the list.""" + + # can only convert equation inputs that have equation string conversion + canconvert = hasattr(equation, "get_equation_string") + + # create remove button + equation_input = gtk.HBox() + removeimage = gtk.Image() + removeimage.set_from_stock(gtk.STOCK_REMOVE, gtk.ICON_SIZE_BUTTON) + removebutton = gtk.Button() + removebutton.add(removeimage) + removebutton.show_all() + equation_input.pack_start(removebutton, expand=False) + equation_input.pack_start(equation) + + # connect button click to remove equation + removebutton.connect("clicked", self._on_remove, equation, + equation_input) + + # create convert to text button + if canconvert: + convertbutton = gtk.Button(_("To Python")) + convertbutton.show_all() + equation_input.pack_start(convertbutton, expand=False) + + def convertequation(widget, data=None): + self._convert_equation(equation, equation_input) + convertbutton.connect("clicked", convertequation) + + # display equation input + equation_input.show() + return equation_input + + + def _add_equation(self, equation): + """Adds an equation to the list.""" + # display equation input + equation_input = self._create_equation(equation) + self._add_equation_input(equation, equation_input) + return equation_input + + + def clear(self): + """Removes all equations from view.""" + self.vbox.foreach(self.vbox.remove) + self._equations = [] + + + +# dictionary of all input view classes +_VIEW_CLASSES = { + _EquationInput.CLASS: _EquationInput, + _PuzzleInput.CLASS: _PuzzleInput +} + |