Changeset 486
- Timestamp:
- 09/04/08 15:44:34 (10 months ago)
- Location:
- nodebox/branches/try-qt-graphics-view/nodebox
- Files:
-
- 6 added
- 3 modified
-
graphics/bezier.py (modified) (1 diff)
-
graphics/qgraphics.py (added)
-
graphics/qt.py (modified) (37 diffs)
-
gui/qt/ValueLadder.py (added)
-
gui/qt/__init__.py (modified) (19 diffs)
-
gui/qt/dashboard.py (added)
-
gui/qt/pytextview.py (added)
-
gui/zoombig.png (added)
-
gui/zoomsmall.png (added)
Legend:
- Unmodified
- Added
- Removed
-
nodebox/branches/try-qt-graphics-view/nodebox/graphics/bezier.py
r155 r486 147 147 if segments == None: 148 148 segments = path.segmentlengths(relative=True) 149 149 150 150 if len(segments) == 0: 151 151 raise NodeBoxError, "The given path is empty" -
nodebox/branches/try-qt-graphics-view/nodebox/graphics/qt.py
r286 r486 3 3 from random import choice, shuffle 4 4 5 from PyQt4.QtGui import QPainterPath, QColor, QTransform, QBrush, QPen, QImage, QPrinter, QPainter, QFontMetrics, QFont6 from PyQt4.QtCore import Qt, QSize, Q PointF, QRectF5 from PyQt4.QtGui import * 6 from PyQt4.QtCore import Qt, QSize, QSizeF, QPointF, QRectF 7 7 from PyQt4.QtSvg import QSvgGenerator 8 8 9 9 from nodebox.util import _copy_attr, _copy_attrs 10 from nodebox.graphics.qgraphics import * 10 11 11 12 __all__ = [ … … 36 37 CORNER = "corner" 37 38 38 MOVETO = 039 LINETO = 140 CURVETO = 241 CLOSE = 339 MOVETO = QPainterPath.MoveToElement 40 LINETO = QPainterPath.LineToElement 41 CURVETO = QPainterPath.CurveToElement 42 CLOSE = "close" 42 43 43 44 LEFT = 0 … … 67 68 '_lineheight': 'lineheight', 68 69 } 69 70 #def _save():71 # NSGraphicsContext.currentContext().saveGraphicsState()72 73 #def _restore():74 # NSGraphicsContext.currentContext().restoreGraphicsState()75 70 76 71 class NodeBoxError(Exception): pass … … 201 196 strokewidth = property(_get_strokewidth, _set_strokewidth) 202 197 198 203 199 class BezierPath(Grob, TransformMixin, ColorMixin): 204 200 """A BezierPath provides a wrapper around QPainterPath.""" … … 212 208 ColorMixin.__init__(self, **kwargs) 213 209 self._segment_cache = None 210 self._qpath_segment_cache = None 214 211 if path is None: 215 212 self._qpath = QPainterPath() … … 237 234 def moveto(self, x, y): 238 235 self._segment_cache = None 236 self._qpath_segment_cache = None 239 237 self._qpath.moveTo(x, y) 240 238 241 239 def lineto(self, x, y): 242 240 self._segment_cache = None 241 self._qpath_segment_cache = None 243 242 self._qpath.lineTo(x, y) 244 243 245 244 def curveto(self, x1, y1, x2, y2, x3, y3): 246 245 self._segment_cache = None 246 self._qpath_segment_cache = None 247 247 self._qpath.cubicTo(x1, y1, x2, y2, x3, y3) 248 248 249 249 def closepath(self): 250 250 self._segment_cache = None 251 self._qpath_segment_cache = None 251 252 self._qpath.closeSubpath() # XXX: Is this correct? 252 253 … … 272 273 def rect(self, x, y, width, height): 273 274 self._segment_cache = None 275 self._qpath_segment_cache = None 274 276 self._qpath.addRect(x, y, width, height) 275 277 276 278 def oval(self, x, y, width, height): 277 279 self._segment_cache = None 280 self._qpath_segment_cache = None 278 281 self._qpath.addEllipse(x, y, width, height) 279 282 280 283 def line(self, x1, y1, x2, y2): 281 284 self._segment_cache = None 285 self._qpath_segment_cache = None 282 286 self._qpath.moveTo(x1, y1) 283 287 self._qpath.lineTo(x2, y2) … … 286 290 287 291 def __getitem__(self, index): 288 el = self._qpath.elementAt(index) 289 return PathElement(el) 292 if self._qpath_segment_cache == None: 293 self._set_qpath_segment_cache() 294 cmd, el = self._qpath_segment_cache[index] 295 return PathElement(cmd, el) 290 296 291 297 def __iter__(self): … … 294 300 295 301 def __len__(self): 296 return self._qpath.elementCount() 302 if self._qpath_segment_cache == None: 303 self._set_qpath_segment_cache() 304 return len(self._qpath_segment_cache) 305 306 def _set_qpath_segment_cache(self): 307 self._qpath_segment_cache = [] 308 length = self._qpath.elementCount() 309 temp = [] 310 for i in range(length): 311 el = self._qpath.elementAt(i) 312 if el.type in [LINETO, MOVETO, CURVETO, CLOSE]: 313 temp.append(i) 314 for i in temp: 315 el = self._qpath.elementAt(i) 316 if el.type in [LINETO, MOVETO, CLOSE]: 317 self._qpath_segment_cache.append((el.type, ((el.x, el.y),))) 318 elif el.type == CURVETO: 319 ctrl1 = self._qpath.elementAt(i+1) 320 ctrl2 = self._qpath.elementAt(i+2) 321 self._qpath_segment_cache.append((el.type, ((el.x, el.y), (ctrl1.x, ctrl1.y), (ctrl2.x, ctrl2.y)))) 297 322 298 323 def extend(self, pathElements): 299 324 self._segment_cache = None 325 self._qpath_segment_cache = None 300 326 for el in pathElements: 301 327 if isinstance(el, (list, tuple)): … … 313 339 def append(self, el): 314 340 self._segment_cache = None 341 self._qpath_segment_cache = None 315 342 if el.cmd == MOVETO: 316 343 self.moveto(el.x, el.y) … … 344 371 transform = property(_get_transform) 345 372 346 def _draw(self, painter): 347 painter.save() 348 self.transform.concat(painter) 373 def _draw(self): 374 item = GraphicsPathItem() 375 self.transform.concat(item) 376 item.setPath(self._qpath) 349 377 if self._fillcolor: 350 painter.fillPath(self._qpath,QBrush(self._fillcolor._rgb))378 item.setBrush(QBrush(self._fillcolor._rgb)) 351 379 if self._strokecolor: 352 380 p = QPen(QBrush(self._strokecolor._rgb), self._strokewidth) 353 painter.setPen(p) 354 painter.drawPath(self._qpath) 355 painter.restore() 381 item.setPen(p) 382 else: 383 item.setPen(QPen(Qt.NoPen)) 384 self._scene.addItem(item) 385 386 def fit(self, x=None, y=None, width=None, height=None, stretch=False): 387 388 """Fits this path to the specified bounds. 389 390 All parameters are optional; if no parameters are specified, nothing will happen. 391 Specifying a parameter will constrain its value: 392 393 - x: The path will be positioned at the specified x value 394 - y: The path will be positioned at the specified y value 395 - width: The path will be of the specified width 396 - height: The path will be of the specified height 397 - stretch: If both width and height are defined, either stretch the path or 398 keep the aspect ratio. 399 """ 400 401 (px, py), (pw, ph) = self.bounds 402 t = Transform() 403 if x is not None and y is None: 404 t.translate(x, py) 405 elif x is None and y is not None: 406 t.translate(px, y) 407 elif x is not None and y is not None: 408 t.translate(x, y) 409 else: 410 t.translate(px, py) 411 if width is not None and height is None: 412 t.scale(width / pw) 413 elif width is None and height is not None: 414 t.scale(height / ph) 415 elif width is not None and height is not None: 416 if stretch: 417 t.scale(width /pw, height / ph) 418 else: 419 t.scale(min(width /pw, height / ph)) 420 t.translate(-px, -py) 421 self._qpath = t.transformBezierPath(self)._qpath 422 self._qpath_segment_cache = None 356 423 357 424 ### Mathematics ### … … 394 461 def addpoint(self, t): 395 462 import bezier 396 self._ nsBezierPath = bezier.insert_point(self, t)._nsBezierPath463 self._qpath = bezier.insert_point(self, t)._qpath 397 464 self._segment_cache = None 465 self._qpath_segment_cache = None 466 467 ### Clipping operations ### 468 469 def intersects(self, other): 470 return self._qpath.intersects(other._qpath) 471 472 def union(self, other, flatness=0.6): 473 return BezierPath(self._ctx, self._qpath.united(other._qpath)) 474 475 def intersect(self, other, flatness=0.6): 476 return BezierPath(self._ctx, self._qpath.intersected(other._qpath)) 477 478 def difference(self, other, flatness=0.6): 479 return BezierPath(self._ctx, self._qpath.subtracted(other._qpath)) 480 481 def xor(self, other, flatness=0.6): 482 union = self._qpath.united(other._qpath) 483 intersection = self._qpath.intersected(other._qpath) 484 return BezierPath(self._ctx, union.subtracted(intersection)) 398 485 399 486 class PathElement(object): … … 446 533 return not self.__eq__(other) 447 534 535 448 536 class ClippingPath(Grob): 449 537 … … 457 545 458 546 def _draw(self): 459 _save()460 547 cp = self.path.transform.transformBezierPath(self.path) 461 cp._nsBezierPath.addClip() 548 item = GraphicsClipItem(self._scene) 549 self._scene.addItem(item) 550 item.setPath(cp._qpath) 551 462 552 for grob in self._grobs: 553 grob._scene = item 463 554 grob._draw() 464 _restore()465 555 466 556 class Rect(BezierPath): … … 468 558 def __init__(self, ctx, x, y, width, height, **kwargs): 469 559 warnings.warn("Rect is deprecated. Use BezierPath's rect method.", DeprecationWarning, stacklevel=2) 470 r = (x,y), (width,height) 471 super(Rect, self).__init__(ctx, NSBezierPath.bezierPathWithRect_(r), **kwargs) 560 p=QPainterPath() 561 p.addRect(x, y, width, height) 562 super(Rect, self).__init__(ctx, p, **kwargs) 472 563 473 564 def copy(self): … … 478 569 def __init__(self, ctx, x, y, width, height, **kwargs): 479 570 warnings.warn("Oval is deprecated. Use BezierPath's oval method.", DeprecationWarning, stacklevel=2) 480 r = (x,y), (width,height) 481 super(Oval, self).__init__(ctx, NSBezierPath.bezierPathWithOvalInRect_(r), **kwargs) 571 p=QPainterPath() 572 p.addEllipse(x, y, width, height) 573 super(Oval, self).__init__(ctx, p, **kwargs) 482 574 483 575 def copy(self): 484 576 raise NotImplementedError, "Please don't use Oval anymore" 485 577 486 578 class Color(object): 487 579 … … 519 611 args = self._normalizeList(args) 520 612 h, s, b = args 613 if h == 1.0: 614 h = .99998 521 615 clr = QColor.fromHsvF(h, s, b, 1) 522 616 elif params == 4 and self._ctx._colormode == RGB: # RGB and alpha … … 527 621 args = self._normalizeList(args) 528 622 h, s, b, a = args 623 if h == 1.0: 624 h = .99998 529 625 clr = QColor.fromHsvF(h, s, b, a) 530 626 elif params == 4 and self._ctx._colormode == CMYK: # CMYK, no alpha … … 557 653 qColor = property(_get_qColor) 558 654 559 560 655 def copy(self): 561 656 new = self.__class__(self._ctx) 562 657 new._rgb = QColor(self._rgb) 563 new._updateCmyk()658 # new._updateCmyk() 564 659 return new 565 660 … … 573 668 574 669 def _get_hue(self): 575 return self._rgb.hueF() 670 hue = self._rgb.hueF() 671 if round(hue, 4) == 1.0: 672 return 1.0 673 if hue < 0.0: 674 return 0.0 675 return hue 576 676 def _set_hue(self, val): 577 677 val = self._normalize(val) 578 c = self._rgb 579 h, s, b, a = c.hueF(), c.saturationF(), c.valueF(), c.alpha() 678 if val == 1.0: 679 val = .99998 680 h, s, b, a = self.hsba 580 681 self._rgb.setHsvF(val, s, b, a) 581 682 self._updateCmyk() 582 683 h = hue = property(_get_hue, _set_hue, doc="the hue of the color") 684 685 def _get_saturation(self): 686 return self._rgb.saturationF() 687 def _set_saturation(self, val): 688 val = self._normalize(val) 689 h, s, b, a = self.hsba 690 self._rgb.setHsvF(h, val, b, a) 691 self._updateCmyk() 692 s = saturation = property(_get_saturation, _set_saturation, doc="the saturation of the color") 693 694 def _get_brightness(self): 695 return self._rgb.valueF() 696 def _set_brightness(self, val): 697 val = self._normalize(val) 698 h, s, b, a = self.hsba 699 self._rgb.setHsvF(h, s, val, a) 700 self._updateCmyk() 701 v = brightness = property(_get_brightness, _set_brightness, doc="the saturation of the color") 702 703 def _get_hsba(self): 704 c = self._rgb 705 return c.hueF(), c.saturationF(), c.valueF(), c.alphaF() 706 def _set_hsba(self, values): 707 values = self._normalizeList(values) 708 h, s, b, a = values 709 self._rgb.setHsvF(h, s, b, a) 710 hsba = property(_get_hsba, _set_hsba, doc="the hue, saturation, brightness and alpha of the color") 711 712 def _get_red(self): 713 return self._rgb.redF() 714 def _set_red(self, val): 715 val = self._normalize(val) 716 r, g, b, a = self.rgba 717 self._rgb.setRgbF(val, g, b, a) 718 self._updateCmyk() 719 r = red = property(_get_red, _set_red, doc="the red component of the color") 720 721 def _get_green(self): 722 return self._rgb.greenF() 723 def _set_green(self, val): 724 val = self._normalize(val) 725 r, g, b, a = self.rgba 726 self._rgb.setRgbF(r, val, b, a) 727 self._updateCmyk() 728 g = green = property(_get_green, _set_green, doc="the green component of the color") 729 730 def _get_blue(self): 731 return self._rgb.blueF() 732 def _set_blue(self, val): 733 val = self._normalize(val) 734 r, g, b, a = self.rgba 735 self._rgb.setRgbF(r, g, val, a) 736 self._updateCmyk() 737 b = blue = property(_get_blue, _set_blue, doc="the blue component of the color") 738 739 def _get_alpha(self): 740 return self._rgb.alphaF() 741 def _set_alpha(self, val): 742 val = self._normalize(val) 743 r, g, b, a = self.rgba 744 self._rgb.setRgbF(r, g, b, val) 745 self._updateCmyk() 746 a = alpha = property(_get_alpha, _set_alpha, doc="the alpha component of the color") 747 748 def _get_rgba(self): 749 c = self._rgb 750 return c.redF(), c.greenF(), c.blueF(), c.alphaF() 751 def _set_rgba(self, values): 752 values = self._normalizeList(values) 753 r, g, b, a = values 754 self._rgb.setRgbF(r, g, b, a) 755 rgba = property(_get_rgba, _set_rgba, doc="the red, green, blue and alpha values of the color") 756 757 def _get_cyan(self): 758 return self._rgb.cyanF() 759 def _set_cyan(self, val): 760 val = self._normalize(val) 761 c, m, y, k, a = self.cmyka 762 self._rgb.setCmykF(val, m, y, k, a) 763 self._updateRgb() 764 c = cyan = property(_get_cyan, _set_cyan, doc="the cyan component of the color") 765 766 def _get_magenta(self): 767 return self._rgb.magentaF() 768 def _set_magenta(self, val): 769 val = self._normalize(val) 770 c, m, y, k, a = self.cmyka 771 self._rgb.setCmykF(c, val, y, k, a) 772 self._updateRgb() 773 m = magenta = property(_get_magenta, _set_magenta, doc="the magenta component of the color") 774 775 def _get_yellow(self): 776 return self._rgb.yellowF() 777 def _set_yellow(self, val): 778 val = self._normalize(val) 779 c, m, y, k, a = self.cmyka 780 self._rgb.setCmykF(c, m, val, k, a) 781 self._updateRgb() 782 y = yellow = property(_get_yellow, _set_yellow, doc="the yellow component of the color") 783 784 def _get_black(self): 785 return self._rgb.blackF() 786 def _set_black(self, val): 787 val = self._normalize(val) 788 c, m, y, k, a = self.cmyka 789 self._rgb.setCmykF(c, m, y, val, a) 790 self._updateRgb() 791 k = black = property(_get_black, _set_black, doc="the black component of the color") 792 793 def _get_cmyka(self): 794 c = self._rgb 795 return c.cyanF(), c.magentaF(), c.yellowF(), c.blackF(), c.alphaF() 796 cmyka = property(_get_cmyka, doc="a tuple containing the CMYKA values for this color") 583 797 584 798 def _normalize(self, v): … … 604 818 elif isinstance(transform, (list, tuple)): 605 819 matrix = tuple(transform) 606 transform = QTransform() 607 transform.setMatrix(*matrix) 820 transform = QTransform(*matrix) 608 821 elif isinstance(transform, QTransform): 609 822 pass … … 622 835 def concat(self, painter): 623 836 trans = painter.transform() 624 painter.setTransform( trans * self._qtransform)837 painter.setTransform(self._qtransform * trans) 625 838 626 839 def copy(self): … … 637 850 def _get_matrix(self): 638 851 q = self._qtransform 639 return (q.m11(), q.m12(), q.m 13(), q.m21(), q.m22(), q.m23(), q.m31(), q.m32(), q.m33())852 return (q.m11(), q.m12(), q.m21(), q.m22(), q.m31(), q.m32()) 640 853 def _set_matrix(self, value): 641 self._qtransform .setMatrix(value)854 self._qtransform = QTransform(*value) 642 855 matrix = property(_get_matrix, _set_matrix) 643 856 … … 657 870 658 871 def skew(self, x=0, y=0): 659 self._qtransform.shear(x, y) 872 import math 873 x = math.pi * x / 180. 874 y = math.pi * y / 180. 875 t = Transform() 876 t.matrix = 1, math.tan(y), -math.tan(x), 1, 0, 0 877 self.prepend(t) 660 878 661 879 def invert(self): … … 711 929 TransformMixin.__init__(self) 712 930 if data is not None: 713 self._ nsImage = QImage(data)931 self._qimage = QImage(data) 714 932 if self._qimage is None: 715 933 raise NodeBoxError, "can't read image %r" % path … … 731 949 if image is None: 732 950 image = QImage(path) 951 pxm = QPixmap.fromImage(image) 733 952 if image is None: 734 953 raise NodeBoxError, "Can't read image %r" % path … … 753 972 754 973 def getSize(self): 755 return self._ nsImage.size()974 return self._qimage.width(), self._qimage.height() 756 975 757 976 size = property(getSize) 758 977 759 def _draw(self , painter):978 def _draw(self): 760 979 """Draw an image on the given coordinates.""" 761 980 762 srcW, srcH = self._qimage.width(), self._qimage.height()981 srcW, srcH = float(self._qimage.width()), float(self._qimage.height()) 763 982 srcRect = ((0, 0), (srcW, srcH)) 983 984 if self.debugImage: 985 item = QGraphicsRectItem() 986 else: 987 item = GraphicsImageItem(self._qimage, self.alpha) 764 988 765 989 # Width or height given … … 771 995 elif self.height is not None: 772 996 factor = self.height / srcH 773 painter.save()774 997 775 998 # Center-mode transforms: translate to image center … … 777 1000 # This is the hardest case: center-mode transformations with given width or height. 778 1001 # Order is very important in this code. 779 780 1002 # Set the position first, before any of the scaling or transformations are done. 781 1003 # Context transformations might change the translation, and we don't want that. 782 1004 t = Transform() 783 1005 t.translate(self.x, self.y) 784 t.concat( painter)785 1006 t.concat(item) 1007 786 1008 # Set new width and height factors. Note that no scaling is done yet: they're just here 787 # to set the new center of the image according to the scaling factors .1009 # to set the new center of the image according to the scaling factors 788 1010 srcW = srcW * factor 789 1011 srcH = srcH * factor 790 1012 791 # Move image to newly calculated center. 1013 # Move image to newly calculated center. 792 1014 dX = srcW / 2 793 1015 dY = srcH / 2 794 1016 t = Transform() 795 1017 t.translate(dX, dY) 796 t.concat( painter)797 1018 t.concat(item) 1019 798 1020 # Do current transformation. 799 self._transform.concat( painter)800 801 # Move back to the previous position. 1021 self._transform.concat(item) 1022 1023 # Move back to the previous position. 802 1024 t = Transform() 803 1025 t.translate(-dX, -dY) 804 t.concat( painter)805 806 # Finally, scale the image according to the factors. 1026 t.concat(item) 1027 1028 # Finally, scale the image according to the factors. 807 1029 t = Transform() 808 1030 t.scale(factor) 809 t.concat( painter)1031 t.concat(item) 810 1032 else: 811 1033 # Do current transformation 812 #self._transform.concat()1034 self._transform.concat(item) 813 1035 # Scale according to width or height factor 814 1036 t = Transform() 815 1037 t.translate(self.x, self.y) # Here we add the positioning of the image. 816 1038 t.scale(factor) 817 t.concat( painter)1039 t.concat(item) 818 1040 819 1041 # A debugImage draws a black rectangle instead of an image. 820 1042 if self.debugImage: 821 painter.setBrush(QBrush(Qt.SolidPattern)) 822 painter.fillRect(QRectF(0, 0, srcW / factor, srcH / factor)) 823 else: 824 # TODO: Stuff with composition modes to allow for alpha transparency 825 painter.drawImage(QPointF(0, 0), self._qimage, QRectF(0, 0, srcW, srcH)) 826 painter.restore() 1043 item.setRect(0, 0, srcW / factor, srcH / factor) 1044 item.setPen(QPen(Qt.NoPen)) 1045 item.setBrush(QBrush(Qt.black)) 1046 1047 self._scene.addItem(item) 827 1048 # No width or height given 828 1049 else: 829 painter.save()830 1050 x,y = self.x, self.y 831 1051 # Center-mode transforms: translate to image center … … 835 1055 t = Transform() 836 1056 t.translate(x+deltaX, y+deltaY) 837 t.concat( painter)1057 t.concat(item) 838 1058 x = -deltaX 839 1059 y = -deltaY 840 1060 # Do current transformation 841 self._transform.concat( painter)1061 self._transform.concat(item) 842 1062 # A debugImage draws a black rectangle instead of an image. 843 1063 if self.debugImage: 844 painter.setBrush(QBrush(Qt.SolidPattern)) 845 painter.fillRect(QRectF(0, 0, srcW, srcH)) 1064 item.setRect(x, y, srcW, srcH) 1065 item.setPen(QPen(Qt.NoPen)) 1066 item.setBrush(QBrush(Qt.black)) 846 1067 else: 847 # TODO: Stuff with composition modes to allow for alpha transparency 848 painter.drawImage(QPointF(0, 0), self._qimage, QRectF(0, 0, srcW, srcH)) 849 painter.restore() 1068 t = Transform() 1069 t.translate(x, y) 1070 t.concat(item) 1071 self._scene.addItem(item) 850 1072 851 1073 class Text(Grob, TransformMixin, ColorMixin): … … 855 1077 856 1078 __dummy_color = QColor() 857 __alignMap = { LEFT: Qt.AlignLeft, RIGHT: Qt.AlignRight, CENTER: Qt.Align Center, JUSTIFY: Qt.AlignJustify }1079 __alignMap = { LEFT: Qt.AlignLeft, RIGHT: Qt.AlignRight, CENTER: Qt.AlignHCenter, JUSTIFY: Qt.AlignJustify } 858 1080 859 1081 def __init__(self, ctx, text, x=0, y=0, width=None, height=None, **kwargs): … … 885 1107 886 1108 def _get_font(self): 887 return QFont(self._fontname, self._fontsize) 1109 f = QFont(self._fontname) 1110 f.setPointSizeF(self._fontsize / textScaleFactor) 1111 return f 888 1112 _qfont = property(_get_font) 889 1113 890 def _draw(self, painter): 891 if self.width is None: 892 w = 100000 893 else: 894 w = self.width 895 if self.height is None: 896 h = 100000 897 else: 898 h = self.height 899 fm = painter.fontMetrics() 900 flags = self.__alignMap[self._align] 901 r = fm.boundingRect(self.x, self.y, w, h, flags, self.text) 902 1114 def _draw(self): 903 1115 if self._fillcolor is None: return 904 x,y = r.x(), r.y() 1116 flags = self.__alignMap[self._align] | Qt.TextWordWrap 1117 fm = QFontMetricsF(self._qfont) 1118 w = self.width or 100000 1119 h = self.height or 100000 1120 preferredWidth, preferredHeight = w, h 1121 r = fm.boundingRect(QRectF(self.x, self.y, w, h), flags, self.text) 1122 x, y = r.x(), r.y() 905 1123 w, h = r.width(), r.height() 906 preferredWidth, preferredHeight = r.width(), r.height()907 1124 if self.width is not None: 908 1125 if self._align == RIGHT: … … 911 1128 x += preferredWidth/2 - w/2 912 1129 913 painter.save() 914 painter.setFont(self._qfont) 915 self._fillcolor._set(painter) 916 #painter.setBrush(QBrush(self._fillcolor)) 1130 textLayout = QTextLayout() 1131 textLayout.setFont(self._qfont) 1132 textLayout.setText(self.text) 1133 opt = QTextOption() 1134 opt.setAlignment(self.__alignMap[self._align]) 1135 opt.setWrapMode(QTextOption.WrapAtWordBoundaryOrAnywhere) 1136 textLayout.setTextOption(opt) 1137 textLayout.beginLayout() 1138 lineSpacing = (fm.ascent() + fm.descent() + fm.leading()) * self._lineheight 1139 1140 advance = 0 1141 while True: 1142 line = textLayout.createLine() 1143 if not line.isValid(): 1144 break 1145 line.setLineWidth(w) 1146 line.setPosition(QPointF(0, advance)) 1147 advance += lineSpacing 1148 textLayout.endLayout() 1149 1150 item = GraphicsTextItem(textLayout, x, y, w, h) 1151 item.setPen(QPen(QBrush(self._fillcolor._rgb), 0)) 1152 917 1153 # Center-mode transforms: translate to image center 918 1154 if self._transformmode == CENTER: 1155 lc = textLayout.lineCount()*lineSpacing 919 1156 deltaX = w / 2 920 1157 deltaY = h / 2 921 1158 t = Transform() 922 #t.translate(x+deltaX, y+fm.ascent()+deltaY) 923 t.concat(painter) 924 self._transform.concat(painter) 925 painter.drawText(x, y, w, h, flags, self.text) 926 #layoutManager.drawGlyphsForGlyphRange_atPoint_(glyphRange, (-deltaX-dx,-deltaY-dy)) 927 else: 928 self._transform.concat() 929 painter.drawText(x, y, w, h, flags, self.text) 930 #layoutManager.drawGlyphsForGlyphRange_atPoint_(glyphRange, (x-dx,y-dy-self.font.defaultLineHeightForFont())) 931 painter.restore() 1159 t.translate(deltaX,lc/2) 1160 t.concat(item) 1161 self._transform.concat(item) 1162 t = Transform() 1163 t.translate(-deltaX,-lc/2) 1164 t.concat(item) 1165 else: 1166 self._transform.concat(item) 1167 self._scene.addItem(item) 932 1168 return (w, h) 933 1169 934 1170 def _get_metrics(self): 935 1171 # TODO: Measure using boundingRect 936 flags = self.__alignMap[self._align] 937 fm = QFontMetrics(self._qfont) 938 939 if self.width is None: 940 w = 100000 941 else: 942 w = self.width 943 if self.height is None: 944 h = 100000 945 else: 946 h = self.height 947 948 r = fm.boundingRect(self.x, self.y, w, h, flags, self.text) 1172 flags = self.__alignMap[self._align] | Qt.TextWordWrap 1173 fm = QFontMetricsF(self._qfont) 1174 w = self.width or 100000 1175 h = self.height or 100000 1176 r = fm.boundingRect(QRectF(self.x, self.y, w, h), flags, self.text) 949 1177 return r.width(), r.height() 950 1178 metrics = property(_get_metrics) … … 1024 1252 self.speed = None 1025 1253 self.mousedown = False 1254 self._scene = None 1026 1255 self.clear() 1027 1256 … … 1059 1288 raise NodeBoxError, "pop: too many canvas pops!" 1060 1289 1061 def draw(self, painter): 1290 def _setTextScaleFactor(self, factor): 1291 global textScaleFactor 1292 textScaleFactor = factor 1293 1294 def draw(self): 1295 self._scene.setSceneRect(0,0,self.width,self.height) 1062 1296 if self.background is not None: 1063 painter.fillRect(0,0, self.width, self.height, self.background._rgb) 1297 self._scene.addRect(QRectF(0,0,self.width,self.height), QPen(Qt.NoPen), QBrush(self.background._rgb)) 1298 self._scene.num += 1 1064 1299 for grob in self._grobs: 1065 grob._draw(painter) 1300 grob._scene = self._scene 1301 grob._draw() 1066 1302 1067 1303 def save(self, fname, format=None): … … 1073 1309 svgGen.setFileName(fname) 1074 1310 svgGen.setSize(QSize(self.width, self.height)) 1075 painter = QPainter(svgGen) 1076 self.draw(painter) 1311 painter = QPainter() 1312 painter.begin(svgGen) 1313 if self._scene: 1314 self._scene.render(painter) 1077 1315 painter.end() 1078 1316 elif format == "pdf": … … 1081 1319 printer.setOutputFileName(fname) 1082 1320 printer.setFullPage(True) 1083 #printer.setPageSize(QPrinter.Custom) 1084 painter = QPainter(printer) 1085 self.draw(painter) 1321 printer.setPaperSize(QSizeF(self.width, self.height), QPrinter.Point) 1322 painter = QPainter() 1323 painter.begin(printer) 1324 if self._scene: 1325 self._scene.render(painter) 1086 1326 painter.end() 1087 1327 elif format in ("png", "tiff", "jpg", "jpeg"): 1088 1328 img = QImage(self.width, self.height, QImage.Format_ARGB32) 1089 painter = QPainter(img) 1090 painter.setRenderHints(QPainter.Antialiasing | QPainter.TextAntialiasing) 1091 self.draw(painter) 1329 painter = QPainter() 1330 painter.begin(img) 1331 painter.setRenderHints(QPainter.Antialiasing | QPainter.TextAntialiasing | QPainter.SmoothPixmapTransform) 1332 if format in ("jpg", "jpeg"): 1333 painter.fillRect(0, 0, self.width, self.height, Qt.white) 1334 if self._scene: 1335 self._scene.render(painter) 1092 1336 painter.end() 1093 1337 img.save(fname, None, 100) -
nodebox/branches/try-qt-graphics-view/nodebox/gui/qt/__init__.py
r286 r486 7 7 import random 8 8 9 from PyQt4.QtGui import QApplication, QWidget, QColor, QPainter, QMenuBar, QMenu, QKeySequence, QTextEdit, QSplitter, QGridLayout, QDialog, QScrollArea, QFont, QTextCharFormat, QFileDialog, QTextCursor, QPixmap, QPrinter, QImage, QMainWindow10 from PyQt4.QtCore import Qt, SIGNAL, SLOT, pyqtSignature, QTimer, QRectF, QSize, QCoreApplication, QSettings, QVariant9 from PyQt4.QtGui import * 10 from PyQt4.QtCore import * 11 11 from PyQt4.QtSvg import QSvgGenerator 12 13 from nodebox.gui.qt.editor import PythonHighlighter, CodeEdit, loadConfig 14 15 MAGICVAR = "__magic_var__" 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 16 17 17 18 from nodebox import graphics … … 32 33 self.data.append((self.isErr, data)) 33 34 34 class NodeBoxGraphicsView(QWidget): 35 35 class GraphicsScene(QGraphicsScene): 36 36 def __init__(self, parent=None): 37 QWidget.__init__(self, parent) 38 self.setMinimumSize(300, 300) 37 QGraphicsScene.__init__(self, parent) 38 self.num = 0 39 40 def addItem(self, item): 41 item.setZValue(self.num) 42 QGraphicsScene.addItem(self, item) 43 self.num += 1 44 45 def removeItem(self, item): 46 QGraphicsScene.removeItem(self, item) 47 self.num -= 1 48 49 def clear(self): 50 try: 51 QGraphicsScene.clear(self) 52 except AttributeError: 53 for item in self.items(): 54 QGraphicsScene.removeItem(self, item) 55 self.num = 0 56 57 def drawItems(self, painter, items, options, widget): 58 painter.setClipRect(self.sceneRect()) 59 QGraphicsScene.drawItems(self, painter, items, options, widget) 60 61 class NodeBoxGraphicsView(QGraphicsView): 62 zoomLevels = [0.1, 0.25, 0.5, 0.75] 63 zoom = 1.0 64 while zoom <= 20.0: 65 zoomLevels.append(zoom) 66 zoom += 1.0 67 68 def __init__(self, parent=None): 69 QGraphicsView.__init__(self) 70 self.setAlignment(Qt.AlignLeft | Qt.AlignTop) 71 self._scene = GraphicsScene(self) 72 self.setScene(self._scene) 73 self._scene.setSceneRect(0,0,1000,1000) 74 self._scene.setItemIndexMethod(QGraphicsScene.NoIndex) 39 75 self._canvas = None 40 76 self._image = None 41 77 self._dirty = True 42 78 self._zoom = 1.0 79 self._dx = 0 80 self._dy = 0 81 self._mouseDown = False 82 83 def scrollContentsBy(self, dx, dy): 84 self._dx -= dx 85 self._dy -= dy 86 QGraphicsView.scrollContentsBy(self, dx, dy) 87 88 def mousePressEvent(self, event): 89 if event.button() == Qt.LeftButton: 90 self._mouseDown = True 91 92 def mouseReleaseEvent(self, event): 93 if event.button() == Qt.LeftButton: 94 self._mouseDown = False 95 96 def mousePosition(self): 97 pos = self.mapFromGlobal(QCursor.pos()) 98 return QPoint(pos.x() + self._dx, pos.y() + self._dy) 99 43 100 def _get_canvas(self): 44 101 return self._canvas 45 102 def _set_canvas(self, canvas): 46 103 self._canvas = canvas 47 size = self.width(), self.height()48 if size != self.canvas.size:49 self.resize(*self.canvas.size)50 104 self.markDirty() 51 105 canvas = property(_get_canvas, _set_canvas) 52 106 107 def _get_zoom(self): 108 return self._zoom 109 def _set_zoom(self, zoom): 110 self._zoom = zoom 111 self.document.zoomLevel.setText("%i%%" % (self._zoom * 100.0)) 112 self.document.zoomSlider.setValue(self._zoom * 100.0) 113 transform = QTransform() 114 transform.scale(self.zoom, self.zoom) 115 self.setTransform( transform) 116 zoom = property(_get_zoom, _set_zoom) 117 118 def findNearestZoomIndex(self, zoom): 119 """Returns the nearest zoom level, and whether we found a direct, exact 120 match or a fuzzy match.""" 121 try: # Search for a direct hit first. 122 idx = self.zoomLevels.index(zoom) 123 return idx, True 124 except ValueError: # Can't find the zoom level, try looking at the indexes. 125 idx = 0 126 try: 127 while self.zoomLevels[idx] < zoom: 128 idx += 1 129 except KeyError: # End of the list 130 idx = len(self.zoomLevels) - 1 # Just return the last index. 131 return idx, False 132 133 def zoomIn_(self): 134 idx, direct = self.findNearestZoomIndex(self.zoom) 135 # Direct hits are perfect, but indirect hits require a bit of help. 136 # Because of the way indirect hits are calculated, they are already 137 # rounded up to the upper zoom level; this means we don't need to add 1. 138 if direct: 139 idx += 1 140 idx = max(min(idx, len(self.zoomLevels)-1), 0) 141 self.zoom = self.zoomLevels[idx] 142 143 def zoomOut_(self): 144 idx, direct = self.findNearestZoomIndex(self.zoom) 145 idx -= 1 146 idx = max(min(idx, len(self.zoomLevels)-1), 0) 147 self.zoom = self.zoomLevels[idx] 148 149 def zoomTo_(self, value): 150 self.zoom = value 151 152 def zoomToFit_(self): 153 w, h = self.canvas.size 154 viewport = self.viewport() 155 fw = viewport.width() 156 fh = viewport.height() 157 factor = min(fw / float(w), fh / float(h)) 158 self.zoom = factor 159 160 def dragZoom_(self, value): 161 self.zoom = value / 100.0 162 53 163 def markDirty(self, redraw=True): 54 164 self._dirty = True 55 165 if redraw: 56 self. repaint()57 166 self._updateImage() 167 58 168 def _updateImage(self): 59 self._image = None60 169 if self.canvas is None: return 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))65 170 try: 66 self.canvas.draw(p) 171 self._scene.clear() 172 if self._scene.width() != self.canvas.width or self._scene.height() != self.canvas.height: 173 self._scene.setSceneRect(QRectF(0, 0, self.canvas.width, self.canvas.height)) 174 self.canvas._scene = self._scene 175 self.canvas.draw() 176 self._scene.update() 67 177 except: 68 178 # A lot of code just to display the error in the output view. … … 75 185 outputView.setTextColor(QColor(255, 0, 0)) # TODO: Refactor color 76 186 outputView.insertPlainText(data) 77 finally:78 p.end() # TODO: This doesn't fix the QWidget warning if error happens during drawing.79 self._image = img80 81 def paintEvent(self, event):82 p = QPainter(self)83 p.setRenderHints(QPainter.Antialiasing | QPainter.TextAntialiasing)84 if self.canvas is None:85 p.fillRect(0, 0, self.width(), self.height(), QColor(Qt.white))86 else:87 if self._dirty:88 self._updateImage()89 p.drawPixmap(0, 0, self._image)90 187 91 188 class NodeBoxDocument(QMainWindow): … … 98 195 self.namespace = {} 99 196 self.canvas = graphics.Canvas() 197 textScaleFactor = QPixmap().logicalDpiX() / 72.0 198 self.canvas._setTextScaleFactor(textScaleFactor) 100 199 self.context = graphics.Context(self.canvas, self.namespace) 101 200 self.animationTimer = None … … 110 209 111 210 def createMenu(self): 112 #self.menuBar = QMenuBar()113 114 211 self.fileMenu = QMenu(self.tr("&File"), self) 115 212 self.fileMenu.addAction(self.tr("&New"), self, SLOT("doNew()"), QKeySequence("Ctrl+N")) … … 134 231 self.editMenu.addAction(self.tr("&Redo"), self.codeView, SLOT("redo()"), QKeySequence("Ctrl+Shift+Z")) 135 232 self.editMenu.addSeparator() 233 self.editMenu.addAction(self.tr("&Switch Viewport"), self, SLOT("switchViewport()"), QKeySequence("Ctrl+Shift+P")) 136 234 self.menuBar().addMenu(self.editMenu) 235 236 self.viewMenu = QMenu(self.tr("&View"), self) 237 self.viewMenu.addAction(self.tr("Zoom &In"), self, SLOT("zoomIn_()"), QKeySequence("Ctrl++")) 238 self.viewMenu.addAction(self.tr("Zoom &Out"), self, SLOT("zoomOut_()"), QKeySequence("Ctrl+-")) 239 self.zoomToMenu = QMenu(self.tr("Zoom to"), self) 240 self.zoomToMenu.addAction(self.tr("To &Fit"), self, SLOT("zoomToFit_()"), QKeySequence("Ctrl+0")) 241 self.zoomToMenu.addAction(self.tr("Actual &Size"), self, SLOT("zoomTo100_()"), QKeySequence("Ctrl+1")) 242 self.zoomToMenu.addAction(self.tr("200%"), self, SLOT("zoomTo200_()"), QKeySequence("Ctrl+2")) 243 self.zoomToMenu.addAction(self.tr("300%"), self, SLOT("zoomTo300_()"), QKeySequence("Ctrl+3")) 244 self.zoomToMenu.addAction(self.tr("400%"), self, SLOT("zoomTo400_()"), QKeySequence("Ctrl+4")) 245 self.zoomToMenu.addAction(self.tr("50%"), self, SLOT("zoomTo50_()"), QKeySequence("Ctrl+5")) 246 self.viewMenu.addMenu(self.zoomToMenu) 247 self.menuBar().addMenu(self.viewMenu) 137 248 138 249 self.pythonMenu = QMenu(self.tr("&Python"), self) 139 250 self.runAction = self.pythonMenu.addAction(self.tr("&Run"), self, SLOT("doRun()"), QKeySequence("Ctrl+R")) 140 self.runAction = self.pythonMenu.addAction(self.tr("&Stop"), self, SLOT("doStop()"), QKeySequence("Ctrl+ ."))251 self.runAction = self.pythonMenu.addAction(self.tr("&Stop"), self, SLOT("doStop()"), QKeySequence("Ctrl+B")) 141 252 self.menuBar().addMenu(self.pythonMenu) 142 253 … … 164 275 codeFormat.setFont(codeFont) 165 276 166 self.graphicsView = NodeBoxGraphicsView() 277 global app 278 self.graphicsView = NodeBoxGraphicsView(self) 167 279 self.graphicsView.document = self 168 self.graphicsView.resize(1000, 1000) 169 self.graphicsScroll = QScrollArea() 170 self.graphicsScroll.setWidget(self.graphicsView) 171 self.graphicsScroll.setMinimumSize(300, 300) 172 self.codeView = CodeEdit() 280 self.graphicsView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn) 281 self.graphicsView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) 282 if app._startgl: 283 self.graphicsView.setViewport(QGLWidget(QGLFormat(QGL.SampleBuffers | QGL.AlphaChannel))) 284 self.graphicsView.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) 285 self._oldViewport = "qwidget" 286 else: 287 self.graphicsView.setViewport(QWidget()) 288 self.graphicsView.setViewportUpdateMode(QGraphicsView.SmartViewportUpdate) 289 self._oldViewport = "qglwidget" 290 self.graphicsView.setOptimizationFlags(QGraphicsView.DontClipPainter | QGraphicsView.DontSavePainterState) 291 292 self.codeView = PyTextView() 293 self.codeView._document = self 173 294 self.codeView.setFontFamily(codeFont.defaultFamily()) 174 295 self.codeView.setCurrentFont(codeFont) … … 176 297 self.codeView.setMinimumSize(300, 300) 177 298 self.codeView.setAcceptRichText(False) 299 self.codeView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn) 300 self.codeView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) 178 301 PythonHighlighter(self.codeView.document()) 179 302 self.outputView = QTextEdit() … … 184 307 self.outputView.setAcceptRichText(False) 185 308 self.outputView.setReadOnly(True) 186 309 self.outputView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) 310 187 311 self.code_errors = QSplitter(Qt.Vertical) 188 312 self.code_errors.addWidget(self.codeView) 189 313 self.code_errors.addWidget(self.outputView) 190 314 315 self.zoomLevel = QLabel("100%") 316 ft = self.zoomLevel.font() 317 ft.setPointSizeF(10) 318 self.zoomLevel.setFont(ft) 319 self.zoomSlider = QSlider(Qt.Horizontal) 320 self.zoomSlider.setMinimumWidth(130) 321 self.zoomSlider.setMinimum(1) 322 self.zoomSlider.setMaximum(1000) 323 self.zoomSlider.setValue(100) 324 self.zoom_small = QPushButton() 325 self.zoom_small.setIcon(QIcon(os.path.join(app.dir_gui, "zoomsmall.png"))) 326 self.zoom_small.setStyleSheet("border: 0;") 327 self.zoom_big = QPushButton() 328 self.zoom_big.setIcon(QIcon(os.path.join(app.dir_gui, "zoombig.png"))) 329 self.zoom_big.setStyleSheet("border: 0;") 330 self.connect(self.zoom_small, SIGNAL("clicked()"), self, SLOT("zoomOut_()")) 331 self.connect(self.zoom_big, SIGNAL("clicked()"), self, SLOT("zoomIn_()")) 332 self.connect(self.zoomSlider, SIGNAL("valueChanged(int)"), self, SLOT("dragZoom_(int)")) 333 334 lh = QHBoxLayout() 335 lh.addWidget(self.zoomLevel) 336 lh.addWidget(self.zoom_small) 337 lh.addWidget(self.zoomSlider) 338 lh.addWidget(self.zoom_big) 339 lh.setContentsMargins(0,0,0,0) 340 lh.setSpacing(8) 341 342 self.zoom = QWidget(self) 343 self.zoom.setLayout(lh) 344 345 lv = QVBoxLayout() 346 lv.addWidget(self.graphicsView) 347 lv.addWidget(self.zoom, 0, Qt.AlignRight) 348 lv.setContentsMargins(0, 0, 0, 0) 349 350 self.graphics_zoom = QWidget(self) 351 self.graphics_zoom.setLayout(lv) 352 191 353 self.view_edit = QSplitter() 192 self.view_edit.addWidget(self.graphics Scroll)354 self.view_edit.addWidget(self.graphics_zoom) 193 355 self.view_edit.addWidget(self.code_errors) 194 356 self.view_edit.setObjectName("view_edit") 195 self.view_edit.setStyleSheet(" QSplitter#view_edit { margin: 10px 10px 20px 10px; border: 0 }")357 self.view_edit.setStyleSheet("#view_edit { margin: 10px 10px 20px 10px; border: 0 }") 196 358 l = QGridLayout() 197 359 l.setHorizontalSpacing(10) 198 360 l.setVerticalSpacing(10) 199 361 self.view_edit.setLayout(l) 200 201 #self.centralWidget = QWidget()202 #self.centralWidget.addWidget(self.view_edit)203 #self.centralWidget.setLayout(QGridLayout())204 205 362 self.setCentralWidget(self.view_edit) 206 363 self.setUnifiedTitleAndToolBarOnMac(True) … … 208 365 209 366 self.setWindowTitle(self.tr("Untitled")) 367 self.dashboardController = DashboardController(self) 210 368 self.resize(800, 600) 211 369 370 @pyqtSignature("") 371 def switchViewport(self): 372 self.outputView.setTextColor(QColor(0,0,0)) 373 if self._oldViewport == "qwidget": 374 self.outputView.insertPlainText("switch to normal view\n") 375 self.graphicsView.setViewport(QWidget()) 376 self.graphicsView.setViewportUpdateMode(QGraphicsView.SmartViewportUpdate) 377 self._oldViewport = "qglwidget" 378 else: 379 self.outputView.insertPlainText("switch to OpenGL view\n") 380 self.graphicsView.setViewport(QGLWidget(QGLFormat(QGL.SampleBuffers | QGL.AlphaChannel))) 381 self.graphicsView.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) 382 self._oldViewport = "qwidget" 383 384 @pyqtSignature("") 385 def zoomIn_(self): 386 if self.fullScreen is not None: return 387 self.graphicsView.zoomIn_() 388 389 @pyqtSignature("") 390 def zoomOut_(self): 391 if self.fullScreen is not None: return 392 self.graphicsView.zoomOut_() 393 394 @pyqtSignature("int") 395 def dragZoom_(self, value): 396 if self.fullScreen is not None: return 397 self.graphicsView.dragZoom_(value) 398 399 @pyqtSignature("") 400 def zoomTo100_(self): 401 if self.fullScreen is not None: return 402 self.graphicsView.zoomTo_(1.0) 403 404 @pyqtSignature("") 405 def zoomTo200_(self): 406 if self.fullScreen is not None: return 407 self.graphicsView.zoomTo_(2.0) 408 409 @pyqtSignature("") 410 def zoomTo300_(self): 411 if self.fullScreen is not None: return 412 self.graphicsView.zoomTo_(3.0) 413 414 @pyqtSignature("") 415 def zoomTo400_(self): 416 if self.fullScreen is not None: return 417 self.graphicsView.zoomTo_(4.0) 418 419 @pyqtSignature("") 420 def zoomTo50_(self): 421 if self.fullScreen is not None: return 422 self.graphicsView.zoomTo_(0.5) 423 424 @pyqtSignature("") 425 def zoomToFit_(self): 426 if self.fullScreen is not None: return 427 self.graphicsView.zoomToFit_() 428 212 429 @pyqtSignature("") 213 430 def doNew(self): … … 279 496 280 497 @pyqtSignature("") 498 def doExportAsMovie(self): 499 pass 500 501 @pyqtSignature("") 502 def doPrint(self): 503 pass 504 505 @pyqtSignature("") 281 506 def doRun(self): 282 507 if self.fullScreen is not None: return … … 317 542 fileName = property(_get_fileName, _set_fileName) 318 543 544 def buildInterface_(self): 545 if not self.dashboardController: 546 self.dashboardController = DashboardController(self) 547 self.dashboardController.buildInterface_(self.vars) 548 319 549 def _runScript(self, compile=True, newSeed=True): 320 if not self.cleanRun(self._execScript ):550 if not self.cleanRun(self._execScript, newSeed): 321 551 pass 322 552 … … 337 567 if self.namespace.has_key("setup"): 338 568 self.fastRun(self.namespace["setup"]) 339 window = self.currentView.window()569 # window = self.currentView.window() 340 570 #window.makeFirstResponder_(self.currentView) 341 571 … … 344 574 self.connect(self.animationTimer, SIGNAL("timeout()"), self, SLOT("doFrame()")) 345 575 self.animationTimer.start(1000.0 / self.speed) 346 576 347 577 def runScriptFast_(self): 348 578 if self.animationTimer is None: … … 365 595 # Build the interface 366 596 self.vars = self.namespace["_ctx"]._vars 367 if len(self.vars) > 0:597 if newSeed and len(self.vars) > 0: 368 598 self.buildInterface_() 369 599 … … 406 636 407 637 # Set the mouse position 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 638 pos = self.currentView.mousePosition() 639 mx, my = pos.x(), pos.y() 640 641 # if isinstance(self.currentView, FullscreenView): 642 # my = self.currentView.bounds()[1][1] - my 643 644 if self.fullScreen is None: 645 mx /= self.currentView.zoom 646 my /= self.currentView.zoom 416 647 self.namespace["MOUSEX"], self.namespace["MOUSEY"] = mx, my 417 #self.namespace["mousedown"] = QApplication.mouseButtons() & Qt.LeftButton648 self.namespace["mousedown"] = self.currentView._mouseDown 418 649 #self.namespace["keydown"] = self.currentView.keydown 419 650 #self.namespace["key"] = self.currentView.key … … 563 794 class FullscreenView(QDialog): 564 795 pass 796 797 def overrideConfig(app): 798 settings = app.settings 799 Config["fontfamily"] = settings.value("fontfamily", 800 QVariant("Monaco")).toString() 801 Config["fontsize"] = settings.value("fontsize", 802 QVariant(11)).toInt()[0] 803 for name, color, bold, italic in ( 804 ("normal", "#000000", False, False), 805 ("keyword", "#0000FF", False, False), 806 ("builtin", "#000000", False, False), 807 ("constant", "#0000FF", False, False), 808 ("decorator", "#000000", False, False), 809 ("comment", "#808080", False, False), 810 ("string", "#FF00FF", False, False), 811 ("number", "#000000", False, False), 812 ("error", "#FF0000", False, False), 813 ("pyqt", "#000000", False, False)): 814 Config["%sfontcolor" % name] = settings.value( 815 "%sfontcolor" % name, QVariant(color)).toString() 816 Config["%sfontbold" % name] = settings.value( 817 "%sfontbold" % name, QVariant(bold)).toBool() 818 Config["%sfontitalic" % name] = settings.value( 819 "%sfontitalic" % name, QVariant(italic)).toBool() 565 820 566 821 class NodeBoxApplication(QApplication): … … 572 827 self.settings = QSettings() 573 828 loadConfig() 829 overrideConfig(self) 574 830 self.documents = [] 575 831 if sys.platform == "win32": … … 591 847 except OSError: pass 592 848 except IOError: pass 593 849 import nodebox.gui 850 dir_gui = nodebox.gui.__file__ 851 self.dir_gui = os.path.split(os.path.realpath(dir_gui))[0] 852 self._startgl = '-gl' in args 853 594 854 def newDocument(self): 595 855 doc = NodeBoxDocument()
