- Timestamp:
- 09/04/08 15:44:34 (19 months ago)
- Files:
-
- 1 modified
Legend:
- Unmodified
- Added
- Removed
-
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)
