Changeset 486
- Timestamp:
- 09/04/08 15:44:34 (4 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)
