| 9 | | from PyQt4.QtGui import QApplication, QWidget, QColor, QPainter, QMenuBar, QMenu, QKeySequence, QTextEdit, QSplitter, QGridLayout, QDialog, QScrollArea, QFont, QTextCharFormat, QFileDialog, QTextCursor, QPixmap, QPrinter, QImage, QMainWindow |
| 10 | | from PyQt4.QtCore import Qt, SIGNAL, SLOT, pyqtSignature, QTimer, QRectF, QSize, QCoreApplication, QSettings, QVariant |
| | 9 | from PyQt4.QtGui import QApplication, QWidget, QColor, QPainter, QMenuBar, QMenu, QKeySequence, QTextEdit, QSplitter, QGridLayout, QDialog, QScrollArea, QFont, QTextCharFormat, QFileDialog, QTextCursor, QPixmap, QPrinter, QImage, QMainWindow, QVBoxLayout, QHBoxLayout, QLabel, QSlider, QPushButton, QIcon, QTransform, QCursor |
| | 10 | from PyQt4.QtCore import Qt, SIGNAL, SLOT, pyqtSignature, QTimer, QRectF, QSize, QCoreApplication, QSettings, QVariant, QPoint |
| 12 | | |
| 13 | | from nodebox.gui.qt.editor import PythonHighlighter, CodeEdit, loadConfig |
| | 12 | from PyQt4.QtOpenGL import QGLWidget, QGLFormat, QGL |
| | 13 | |
| | 14 | from nodebox.gui.qt.ValueLadder import MAGICVAR |
| | 15 | from nodebox.gui.qt.pytextview import PythonHighlighter, PyTextView, loadConfig, Config |
| | 16 | from nodebox.gui.qt.dashboard import DashboardController |
| 47 | | size = self.width(), self.height() |
| 48 | | if size != self.canvas.size: |
| 49 | | self.resize(*self.canvas.size) |
| | 67 | if canvas is not None: |
| | 68 | size = int(self.width()/float(self._zoom)), int(self.height()/float(self._zoom)) |
| | 69 | if size != self.canvas.size: |
| | 70 | width, height = self.canvas.size |
| | 71 | self.resize(width*self._zoom, height*self._zoom) |
| | 75 | def _get_zoom(self): |
| | 76 | return self._zoom |
| | 77 | def _set_zoom(self, zoom): |
| | 78 | self._zoom = zoom |
| | 79 | self.document.zoomLevel.setText("%i%%" % (self._zoom * 100.0)) |
| | 80 | self.document.zoomSlider.setValue(self._zoom * 100.0) |
| | 81 | self.canvas = self.canvas |
| | 82 | zoom = property(_get_zoom, _set_zoom) |
| | 83 | |
| | 84 | def findNearestZoomIndex(self, zoom): |
| | 85 | """Returns the nearest zoom level, and whether we found a direct, exact |
| | 86 | match or a fuzzy match.""" |
| | 87 | try: # Search for a direct hit first. |
| | 88 | idx = self.zoomLevels.index(zoom) |
| | 89 | return idx, True |
| | 90 | except ValueError: # Can't find the zoom level, try looking at the indexes. |
| | 91 | idx = 0 |
| | 92 | try: |
| | 93 | while self.zoomLevels[idx] < zoom: |
| | 94 | idx += 1 |
| | 95 | except KeyError: # End of the list |
| | 96 | idx = len(self.zoomLevels) - 1 # Just return the last index. |
| | 97 | return idx, False |
| | 98 | |
| | 99 | def zoomIn_(self): |
| | 100 | idx, direct = self.findNearestZoomIndex(self.zoom) |
| | 101 | # Direct hits are perfect, but indirect hits require a bit of help. |
| | 102 | # Because of the way indirect hits are calculated, they are already |
| | 103 | # rounded up to the upper zoom level; this means we don't need to add 1. |
| | 104 | if direct: |
| | 105 | idx += 1 |
| | 106 | idx = max(min(idx, len(self.zoomLevels)-1), 0) |
| | 107 | self.zoom = self.zoomLevels[idx] |
| | 108 | |
| | 109 | def zoomOut_(self): |
| | 110 | idx, direct = self.findNearestZoomIndex(self.zoom) |
| | 111 | idx -= 1 |
| | 112 | idx = max(min(idx, len(self.zoomLevels)-1), 0) |
| | 113 | self.zoom = self.zoomLevels[idx] |
| | 114 | |
| | 115 | def zoomTo_(self, value): |
| | 116 | self.zoom = value |
| | 117 | |
| | 118 | def zoomToFit_(self, scroll): |
| | 119 | w, h = self.canvas.size |
| | 120 | viewport = scroll.viewport() |
| | 121 | fw = viewport.width() |
| | 122 | fh = viewport.height() |
| | 123 | factor = min(fw / float(w), fh / float(h)) |
| | 124 | self.zoom = factor |
| | 125 | |
| | 126 | def dragZoom_(self, value): |
| | 127 | self.zoom = value / 100.0 |
| | 128 | |
| 61 | | img = QPixmap(self.canvas.width, self.canvas.height) |
| 62 | | p = QPainter(img) |
| 63 | | p.setRenderHints(QPainter.Antialiasing | QPainter.TextAntialiasing) |
| 64 | | p.setClipRect(QRectF(0, 0, self.canvas.width, self.canvas.height)) |
| | 137 | p = QPainter() |
| | 138 | p.begin(self) |
| | 139 | p.setRenderHints(QPainter.Antialiasing | QPainter.TextAntialiasing | QPainter.SmoothPixmapTransform | QPainter.HighQualityAntialiasing) |
| | 140 | p.setClipRect(QRectF(0, 0, self.canvas.width * self.zoom, self.canvas.height * self.zoom)) |
| | 141 | |
| | 142 | if self.zoom != 1.0: |
| | 143 | p.scale(self.zoom, self.zoom) |
| 89 | | p.drawPixmap(0, 0, self._image) |
| 90 | | |
| | 168 | |
| | 169 | class QGLNodeBoxGraphicsView(QGLWidget, NodeBoxGraphicsView): |
| | 170 | def __init__(self, parent=None): |
| | 171 | QGLWidget.__init__(self, QGLFormat(QGL.SampleBuffers | QGL.AlphaChannel), parent) |
| | 172 | NodeBoxGraphicsView.__init__(self) |
| | 173 | |
| | 174 | class QNodeBoxGraphicsView(QWidget, NodeBoxGraphicsView): |
| | 175 | def __init__(self, parent=None): |
| | 176 | QWidget.__init__(self, parent) |
| | 177 | NodeBoxGraphicsView.__init__(self) |
| | 178 | |
| | 226 | self.viewMenu = QMenu(self.tr("&View"), self) |
| | 227 | self.viewMenu.addAction(self.tr("Zoom &In"), self, SLOT("zoomIn_()"), QKeySequence("Ctrl++")) |
| | 228 | self.viewMenu.addAction(self.tr("Zoom &Out"), self, SLOT("zoomOut_()"), QKeySequence("Ctrl+-")) |
| | 229 | self.zoomToMenu = QMenu(self.tr("Zoom to"), self) |
| | 230 | self.zoomToMenu.addAction(self.tr("To &Fit"), self, SLOT("zoomToFit_()"), QKeySequence("Ctrl+0")) |
| | 231 | self.zoomToMenu.addAction(self.tr("Actual &Size"), self, SLOT("zoomTo100_()"), QKeySequence("Ctrl+1")) |
| | 232 | self.zoomToMenu.addAction(self.tr("200%"), self, SLOT("zoomTo200_()"), QKeySequence("Ctrl+2")) |
| | 233 | self.zoomToMenu.addAction(self.tr("300%"), self, SLOT("zoomTo300_()"), QKeySequence("Ctrl+3")) |
| | 234 | self.zoomToMenu.addAction(self.tr("400%"), self, SLOT("zoomTo400_()"), QKeySequence("Ctrl+4")) |
| | 235 | self.zoomToMenu.addAction(self.tr("50%"), self, SLOT("zoomTo50_()"), QKeySequence("Ctrl+5")) |
| | 236 | self.viewMenu.addMenu(self.zoomToMenu) |
| | 237 | self.menuBar().addMenu(self.viewMenu) |
| | 238 | |
| | 298 | self.zoomLevel = QLabel("100%") |
| | 299 | ft = self.zoomLevel.font() |
| | 300 | ft.setPointSizeF(10) |
| | 301 | self.zoomLevel.setFont(ft) |
| | 302 | self.zoomSlider = QSlider(Qt.Horizontal) |
| | 303 | self.zoomSlider.setMinimumWidth(130) |
| | 304 | self.zoomSlider.setMinimum(1) |
| | 305 | self.zoomSlider.setMaximum(1000) |
| | 306 | self.zoomSlider.setValue(100) |
| | 307 | self.zoom_small = QPushButton() |
| | 308 | self.zoom_small.setIcon(QIcon(os.path.join(app.dir_gui, "zoomsmall.png"))) |
| | 309 | self.zoom_small.setStyleSheet("border: 0;") |
| | 310 | self.zoom_big = QPushButton() |
| | 311 | self.zoom_big.setIcon(QIcon(os.path.join(app.dir_gui, "zoombig.png"))) |
| | 312 | self.zoom_big.setStyleSheet("border: 0;") |
| | 313 | self.connect(self.zoom_small, SIGNAL("clicked()"), self, SLOT("zoomOut_()")) |
| | 314 | self.connect(self.zoom_big, SIGNAL("clicked()"), self, SLOT("zoomIn_()")) |
| | 315 | self.connect(self.zoomSlider, SIGNAL("valueChanged(int)"), self, SLOT("dragZoom_(int)")) |
| | 316 | |
| | 317 | lh = QHBoxLayout() |
| | 318 | lh.addWidget(self.zoomLevel) |
| | 319 | lh.addWidget(self.zoom_small) |
| | 320 | lh.addWidget(self.zoomSlider) |
| | 321 | lh.addWidget(self.zoom_big) |
| | 322 | lh.setContentsMargins(0,0,0,0) |
| | 323 | lh.setSpacing(8) |
| | 324 | |
| | 325 | self.zoom = QWidget(self) |
| | 326 | self.zoom.setLayout(lh) |
| | 327 | |
| | 328 | lv = QVBoxLayout() |
| | 329 | lv.addWidget(self.graphicsScroll) |
| | 330 | lv.addWidget(self.zoom, 0, Qt.AlignRight) |
| | 331 | lv.setContentsMargins(0, 0, 0, 0) |
| | 332 | |
| | 333 | self.graphics_zoom = QWidget(self) |
| | 334 | self.graphics_zoom.setLayout(lv) |
| | 335 | |
| 211 | | |
| | 352 | |
| | 353 | @pyqtSignature("") |
| | 354 | def zoomIn_(self): |
| | 355 | if self.fullScreen is not None: return |
| | 356 | self.graphicsView.zoomIn_() |
| | 357 | |
| | 358 | @pyqtSignature("") |
| | 359 | def zoomOut_(self): |
| | 360 | if self.fullScreen is not None: return |
| | 361 | self.graphicsView.zoomOut_() |
| | 362 | |
| | 363 | @pyqtSignature("int") |
| | 364 | def dragZoom_(self, value): |
| | 365 | if self.fullScreen is not None: return |
| | 366 | self.graphicsView.dragZoom_(value) |
| | 367 | |
| | 368 | @pyqtSignature("") |
| | 369 | def zoomTo100_(self): |
| | 370 | if self.fullScreen is not None: return |
| | 371 | self.graphicsView.zoomTo_(1.0) |
| | 372 | |
| | 373 | @pyqtSignature("") |
| | 374 | def zoomTo200_(self): |
| | 375 | if self.fullScreen is not None: return |
| | 376 | self.graphicsView.zoomTo_(2.0) |
| | 377 | |
| | 378 | @pyqtSignature("") |
| | 379 | def zoomTo300_(self): |
| | 380 | if self.fullScreen is not None: return |
| | 381 | self.graphicsView.zoomTo_(3.0) |
| | 382 | |
| | 383 | @pyqtSignature("") |
| | 384 | def zoomTo400_(self): |
| | 385 | if self.fullScreen is not None: return |
| | 386 | self.graphicsView.zoomTo_(4.0) |
| | 387 | |
| | 388 | @pyqtSignature("") |
| | 389 | def zoomTo50_(self): |
| | 390 | if self.fullScreen is not None: return |
| | 391 | self.graphicsView.zoomTo_(0.5) |
| | 392 | |
| | 393 | @pyqtSignature("") |
| | 394 | def zoomToFit_(self): |
| | 395 | if self.fullScreen is not None: return |
| | 396 | self.graphicsView.zoomToFit_(self.graphicsScroll) |
| | 397 | |
| 408 | | # TODO: Get correct mouse position |
| 409 | | #window = self.currentView.window() |
| 410 | | pt = 0, 0 # window.mouseLocationOutsideOfEventStream() |
| 411 | | mx, my = 0, 0 # window.contentView().convertPoint_toView_(pt, self.currentView) |
| 412 | | # Hack: mouse coordinates are flipped vertically in FullscreenView. |
| 413 | | # This flips them back. |
| 414 | | if isinstance(self.currentView, FullscreenView): |
| 415 | | my = self.currentView.bounds()[1][1] - my |
| | 607 | pos = self.currentView.mousePosition() |
| | 608 | mx, my = pos.x(), pos.y() |
| | 609 | |
| | 610 | # if isinstance(self.currentView, FullscreenView): |
| | 611 | # my = self.currentView.bounds()[1][1] - my |
| | 612 | |
| | 613 | if self.fullScreen is None: |
| | 614 | mx /= self.currentView.zoom |
| | 615 | my /= self.currentView.zoom |
| | 765 | |
| | 766 | def overrideConfig(app): |
| | 767 | settings = app.settings |
| | 768 | Config["fontfamily"] = settings.value("fontfamily", |
| | 769 | QVariant("Monaco")).toString() |
| | 770 | Config["fontsize"] = settings.value("fontsize", |
| | 771 | QVariant(11)).toInt()[0] |
| | 772 | for name, color, bold, italic in ( |
| | 773 | ("normal", "#000000", False, False), |
| | 774 | ("keyword", "#0000FF", False, False), |
| | 775 | ("builtin", "#000000", False, False), |
| | 776 | ("constant", "#0000FF", False, False), |
| | 777 | ("decorator", "#000000", False, False), |
| | 778 | ("comment", "#808080", False, False), |
| | 779 | ("string", "#FF00FF", False, False), |
| | 780 | ("number", "#000000", False, False), |
| | 781 | ("error", "#FF0000", False, False), |
| | 782 | ("pyqt", "#000000", False, False)): |
| | 783 | Config["%sfontcolor" % name] = settings.value( |
| | 784 | "%sfontcolor" % name, QVariant(color)).toString() |
| | 785 | Config["%sfontbold" % name] = settings.value( |
| | 786 | "%sfontbold" % name, QVariant(bold)).toBool() |
| | 787 | Config["%sfontitalic" % name] = settings.value( |
| | 788 | "%sfontitalic" % name, QVariant(italic)).toBool() |