class Controller(QtCore.QObject): def __init__(self, ui): super(Controller, self).__init__() self.ui = ui self.scene_model = QtGui.QGraphicsScene() self.ui.display.setScene(self.scene_model) # FIXME: Should be dynamic, scrolling should be limited, # perhaps. Zoomable. # N.b. reflection in Y. self.ui.display.scale(100, -100) self.surface = RiemannSurface() self.indets = None csr = CentralSurfaceRenderer(self.scene_model, self.surface) self.surface_renderer = csr self.paths = PathManager(self.ui.paths) self.ui.paths.setModel(self.paths) self.scroll_locked = False self._connectSlots() self._setStandardIcons() self.surfaceChanged() # QGraphicsView::fitInView(QRectF&, Qt::AspectRatioMode) to set zoom. # Scroll wheel for zoom too. # May want to lock scroll-bars on or off def _connectSlots(self): self.ui.equation.editingFinished.connect(self.surfaceChanged) self.ui.projection_variable.currentIndexChanged.connect(self.setProjection) self.ui.primary_mode.currentChanged.connect(self.setPrimaryMode) self.surface_renderer.centralPointDragged.connect(self.centralPointDragged) self.ui.central_point.editingFinished.connect(self.centralPointSetTextually) self.ui.add_path.clicked.connect(self.paths.newPath) self.ui.delete_path.clicked.connect(self.paths.removeSelectedPaths) def _setStandardIcons(self): # Unfortunately Qt Designer doesn't have a way to set the # standard icons yet so we have to do it manually here. self.ui.add_path.setIcon(QtGui.QIcon.fromTheme('list-add')) self.ui.delete_path.setIcon(QtGui.QIcon.fromTheme('list-remove')) self.ui.zoom_in.setIcon(QtGui.QIcon.fromTheme('zoom-in')) self.ui.zoom_out.setIcon(QtGui.QIcon.fromTheme('zoom-out')) self._setScrollLockIcon() def _setScrollLockIcon(self): if self.scroll_locked: self.ui.scroll_lock.setIcon(QtGui.QIcon.fromTheme('object-locked')) else: self.ui.scroll_lock.setIcon(QtGui.QIcon.fromTheme('object-unlocked')) def updatePermittedProjections(self): '''Called when the equation defining the Riemann surface is changed, this function harvests the indeterminates in the polynomial and updates the ''' combo = self.ui.projection_variable if self.surface.indeterminates() == self.indets: return self.indets = self.surface.indeterminates() combo.clear() for indet in self.indets: combo.addItem(str(indet) + ' plane') combo.setCurrentIndex(0) # A reasonably sane default # Signals/slots we might care about: # scene_model.selectionChanged # Signals: # Slots: def setPrimaryMode(self, index): '''Currently there are two modes: editing the surface itself, and editing paths defined on that surface. The mode in use should be determined by the active tab at the bottom.''' if index == 0: self.surface_renderer.setEditMode(True) else: self.surface_renderer.setEditMode(False) def surfaceChanged(self): '''Deals with the defining-equation of the Riemann surface being changed''' new_text = self.ui.equation.text() self.surface.setEquation(new_text) self.surface_renderer.surfaceOrProjectionChanged(self.surface) self.updatePermittedProjections() # FIXME: highlight incorrect syntax def setProjection(self, idx): self.surface.setProjectsOnto(self.indets[idx]) self.surface_renderer.surfaceOrProjectionChanged(self.surface) def centralPointSet(self, new_text): pass def centralPointDragged(self, new_point): text = '%f+%f*I' % (new_point.x(), new_point.y()) self.ui.central_point.setText(text) def centralPointSetTextually(self): new_point = self.ui.central_point.text() try: new_point = complex(parse_expr(new_point)) self.surface_renderer.setCentralPoint(new_point) except ValueError: return