Changeset 484

Show
Ignore:
Timestamp:
09/04/08 15:29:15 (19 months ago)
Author:
stefan
Message:

initial changes

Location:
nodebox/branches/try-qt-painter/nodebox
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • nodebox/branches/try-qt-painter/nodebox/graphics/qt.py

    r286 r484  
    33from random import choice, shuffle 
    44 
    5 from PyQt4.QtGui import QPainterPath, QColor, QTransform, QBrush, QPen, QImage, QPrinter, QPainter, QFontMetrics, QFont 
     5from PyQt4.QtGui import QPainterPath, QColor, QTransform, QBrush, QPen, QImage, QPrinter, QPainter, QFontMetrics, QFontMetricsF, QFont, QTextLayout, QTextOption 
    66from PyQt4.QtCore import Qt, QSize, QPointF, QRectF 
    77from PyQt4.QtSvg import QSvgGenerator 
     
    3636CORNER = "corner" 
    3737 
    38 MOVETO = 0 
    39 LINETO = 1 
    40 CURVETO = 2 
    41 CLOSE = 3 
     38MOVETO = QPainterPath.MoveToElement 
     39LINETO = QPainterPath.LineToElement 
     40CURVETO = QPainterPath.CurveToElement 
     41CLOSE = "close" 
    4242 
    4343LEFT = 0 
     
    212212        ColorMixin.__init__(self, **kwargs) 
    213213        self._segment_cache = None 
     214        self._qpath_segment_cache = None 
    214215        if path is None: 
    215216            self._qpath = QPainterPath() 
     
    237238    def moveto(self, x, y): 
    238239        self._segment_cache = None 
     240        self._qpath_segment_cache = None 
    239241        self._qpath.moveTo(x, y) 
    240242 
    241243    def lineto(self, x, y): 
    242244        self._segment_cache = None 
     245        self._qpath_segment_cache = None 
    243246        self._qpath.lineTo(x, y) 
    244247 
    245248    def curveto(self, x1, y1, x2, y2, x3, y3): 
    246249        self._segment_cache = None 
     250        self._qpath_segment_cache = None 
    247251        self._qpath.cubicTo(x1, y1, x2, y2, x3, y3) 
    248252 
    249253    def closepath(self): 
    250254        self._segment_cache = None 
     255        self._qpath_segment_cache = None 
    251256        self._qpath.closeSubpath() # XXX: Is this correct? 
    252257 
     
    272277    def rect(self, x, y, width, height): 
    273278        self._segment_cache = None 
     279        self._qpath_segment_cache = None 
    274280        self._qpath.addRect(x, y, width, height) 
    275281         
    276282    def oval(self, x, y, width, height): 
    277283        self._segment_cache = None 
     284        self._qpath_segment_cache = None 
    278285        self._qpath.addEllipse(x, y, width, height) 
    279286         
    280287    def line(self, x1, y1, x2, y2): 
    281288        self._segment_cache = None 
     289        self._qpath_segment_cache = None 
    282290        self._qpath.moveTo(x1, y1) 
    283291        self._qpath.lineTo(x2, y2) 
     
    286294 
    287295    def __getitem__(self, index): 
    288         el = self._qpath.elementAt(index) 
    289         return PathElement(el) 
     296        if self._qpath_segment_cache == None: 
     297            self._set_qpath_segment_cache() 
     298        cmd, el = self._qpath_segment_cache[index] 
     299        return PathElement(cmd, el) 
    290300 
    291301    def __iter__(self): 
     
    294304 
    295305    def __len__(self): 
    296         return self._qpath.elementCount() 
     306        if self._qpath_segment_cache == None: 
     307            self._set_qpath_segment_cache() 
     308        return len(self._qpath_segment_cache) 
     309 
     310    def _set_qpath_segment_cache(self): 
     311        self._qpath_segment_cache = [] 
     312        length = self._qpath.elementCount() 
     313        temp = [] 
     314        for i in range(length): 
     315            el = self._qpath.elementAt(i) 
     316            if el.type in [LINETO, MOVETO, CURVETO, CLOSE]: 
     317                temp.append(i) 
     318        for i in temp: 
     319            el = self._qpath.elementAt(i) 
     320            if el.type in [LINETO, MOVETO, CLOSE]: 
     321                self._qpath_segment_cache.append((el.type, ((el.x, el.y),))) 
     322            elif el.type == CURVETO: 
     323                ctrl1 = self._qpath.elementAt(i+1) 
     324                ctrl2 = self._qpath.elementAt(i+2) 
     325                self._qpath_segment_cache.append((el.type, ((el.x, el.y), (ctrl1.x, ctrl1.y), (ctrl2.x, ctrl2.y)))) 
    297326 
    298327    def extend(self, pathElements): 
    299328        self._segment_cache = None 
     329        self._qpath_segment_cache = None 
    300330        for el in pathElements: 
    301331            if isinstance(el, (list, tuple)): 
     
    313343    def append(self, el): 
    314344        self._segment_cache = None 
     345        self._qpath_segment_cache = None 
    315346        if el.cmd == MOVETO: 
    316347            self.moveto(el.x, el.y) 
     
    355386        painter.restore() 
    356387         
     388    def fit(self, x=None, y=None, width=None, height=None, stretch=False): 
     389 
     390        """Fits this path to the specified bounds. 
     391     
     392        All parameters are optional; if no parameters are specified, nothing will happen. 
     393        Specifying a parameter will constrain its value: 
     394     
     395        - x: The path will be positioned at the specified x value 
     396        - y: The path will be positioned at the specified y value 
     397        - width: The path will be of the specified width 
     398        - height: The path will be of the specified height 
     399        - stretch: If both width and height are defined, either stretch the path or 
     400                keep the aspect ratio. 
     401        """ 
     402 
     403        (px, py), (pw, ph) = self.bounds 
     404        t = Transform() 
     405        if x is not None and y is None: 
     406            t.translate(x, py) 
     407        elif x is None and y is not None: 
     408            t.translate(px, y) 
     409        elif x is not None and y is not None: 
     410            t.translate(x, y) 
     411        else: 
     412            t.translate(px, py) 
     413        if width is not None and height is None: 
     414            t.scale(width / pw) 
     415        elif width is None and height is not None: 
     416            t.scale(height / ph) 
     417        elif width is not None and height is not None: 
     418            if stretch: 
     419                t.scale(width /pw, height / ph) 
     420            else: 
     421                t.scale(min(width /pw, height / ph)) 
     422        t.translate(-px, -py) 
     423        self._qpath = t.transformBezierPath(self)._qpath 
     424         
    357425    ### Mathematics ### 
    358426     
     
    394462    def addpoint(self, t): 
    395463        import bezier 
    396         self._nsBezierPath = bezier.insert_point(self, t)._nsBezierPath 
     464        self._qPath = bezier.insert_point(self, t)._qPath 
    397465        self._segment_cache = None 
     466        self._qpath_segment_cache = None 
     467 
     468    ### Clipping operations ### 
     469 
     470    def intersects(self, other): 
     471        return self._qpath.intersects(other._qpath) 
     472 
     473    def union(self, other, flatness=0.6): 
     474        return BezierPath(self._ctx, self._qpath.united(other._qpath)) 
     475 
     476    def intersect(self, other, flatness=0.6): 
     477        return BezierPath(self._ctx, self._qpath.intersected(other._qpath)) 
     478 
     479    def difference(self, other, flatness=0.6): 
     480        return BezierPath(self._ctx, self._qpath.subtracted(other._qpath)) 
     481 
     482    def xor(self, other, flatness=0.6): 
     483        union = self._qpath.united(other._qpath) 
     484        intersection = self._qpath.intersected(other._qpath) 
     485        return BezierPath(self._ctx, union.subtracted(intersection)) 
    398486 
    399487class PathElement(object): 
     
    456544        self._grobs.append(grob) 
    457545         
    458     def _draw(self): 
    459         _save() 
    460         cp = self.path.transform.transformBezierPath(self.path) 
    461         cp._nsBezierPath.addClip() 
     546    def _draw(self, painter): 
     547        painter.save() 
     548        transform = self.path.transform 
     549        cp = transform.transformBezierPath(self.path) 
     550        painter.setClipPath(cp._qpath) 
    462551        for grob in self._grobs: 
    463             grob._draw() 
    464         _restore() 
     552            grob._draw(painter) 
     553        painter.restore() 
    465554 
    466555class Rect(BezierPath): 
     
    468557    def __init__(self, ctx, x, y, width, height, **kwargs): 
    469558        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) 
     559        p=QPainterPath() 
     560        p.addRect(x, y, width, height) 
     561        super(Rect, self).__init__(ctx, p, **kwargs) 
    472562 
    473563    def copy(self): 
     
    478568    def __init__(self, ctx, x, y, width, height, **kwargs): 
    479569        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) 
     570        p=QPainterPath() 
     571        p.addEllipse(x, y, width, height) 
     572        super(Oval, self).__init__(ctx, p, **kwargs) 
    482573 
    483574    def copy(self): 
     
    519610            args = self._normalizeList(args) 
    520611            h, s, b = args 
     612            if h == 1.0: 
     613                h = .99998 
    521614            clr = QColor.fromHsvF(h, s, b, 1) 
    522615        elif params == 4 and self._ctx._colormode == RGB: # RGB and alpha 
     
    527620            args = self._normalizeList(args) 
    528621            h, s, b, a = args 
     622            if h == 1.0: 
     623                h = .99998 
    529624            clr = QColor.fromHsvF(h, s, b, a) 
    530625        elif params == 4 and self._ctx._colormode == CMYK: # CMYK, no alpha 
     
    557652    qColor = property(_get_qColor) 
    558653         
    559  
    560654    def copy(self): 
    561655        new = self.__class__(self._ctx) 
    562656        new._rgb = QColor(self._rgb) 
    563         new._updateCmyk() 
     657#        new._updateCmyk() 
    564658        return new 
    565659 
     
    573667 
    574668    def _get_hue(self): 
    575         return self._rgb.hueF() 
     669        hue = self._rgb.hueF() 
     670        if round(hue, 4) == 1.0: 
     671            return 1.0 
     672        if hue < 0.0: 
     673            return 0.0 
     674        return hue 
    576675    def _set_hue(self, val): 
    577676        val = self._normalize(val) 
    578         c = self._rgb 
    579         h, s, b, a = c.hueF(), c.saturationF(), c.valueF(), c.alpha() 
     677        if val == 1.0: 
     678           val = .99998 
     679        h, s, b, a = self.hsba 
    580680        self._rgb.setHsvF(val, s, b, a) 
    581681        self._updateCmyk() 
    582682    h = hue = property(_get_hue, _set_hue, doc="the hue of the color") 
     683 
     684    def _get_saturation(self): 
     685        return self._rgb.saturationF() 
     686    def _set_saturation(self, val): 
     687        val = self._normalize(val) 
     688        h, s, b, a = self.hsba 
     689        self._rgb.setHsvF(h, val, b, a) 
     690        self._updateCmyk() 
     691    s = saturation = property(_get_saturation, _set_saturation, doc="the saturation of the color") 
     692 
     693    def _get_brightness(self): 
     694        return self._rgb.valueF() 
     695    def _set_brightness(self, val): 
     696        val = self._normalize(val) 
     697        h, s, b, a = self.hsba 
     698        self._rgb.setHsvF(h, s, val, a) 
     699        self._updateCmyk() 
     700    v = brightness = property(_get_brightness, _set_brightness, doc="the saturation of the color") 
     701 
     702    def _get_hsba(self): 
     703        c = self._rgb 
     704        return c.hueF(), c.saturationF(), c.valueF(), c.alphaF() 
     705    def _set_hsba(self, values): 
     706        values = self._normalizeList(values) 
     707        h, s, b, a = values 
     708        self._rgb.setHsvF(h, s, b, a) 
     709    hsba = property(_get_hsba, _set_hsba, doc="the hue, saturation, brightness and alpha of the color") 
     710 
     711    def _get_red(self): 
     712        return self._rgb.redF() 
     713    def _set_red(self, val): 
     714        val = self._normalize(val) 
     715        r, g, b, a = self.rgba 
     716        self._rgb.setRgbF(val, g, b, a) 
     717        self._updateCmyk()         
     718    r = red = property(_get_red, _set_red, doc="the red component of the color") 
     719 
     720    def _get_green(self): 
     721        return self._rgb.greenF() 
     722    def _set_green(self, val): 
     723        val = self._normalize(val) 
     724        r, g, b, a = self.rgba 
     725        self._rgb.setRgbF(r, val, b, a) 
     726        self._updateCmyk()         
     727    g = green = property(_get_green, _set_green, doc="the green component of the color") 
     728 
     729    def _get_blue(self): 
     730        return self._rgb.blueF() 
     731    def _set_blue(self, val): 
     732        val = self._normalize(val) 
     733        r, g, b, a = self.rgba 
     734        self._rgb.setRgbF(r, g, val, a) 
     735        self._updateCmyk()         
     736    b = blue = property(_get_blue, _set_blue, doc="the blue component of the color") 
     737 
     738    def _get_alpha(self): 
     739        return self._rgb.alphaF() 
     740    def _set_alpha(self, val): 
     741        val = self._normalize(val) 
     742        r, g, b, a = self.rgba 
     743        self._rgb.setRgbF(r, g, b, val) 
     744        self._updateCmyk()         
     745    a = alpha = property(_get_alpha, _set_alpha, doc="the alpha component of the color") 
     746    
     747    def _get_rgba(self): 
     748        c = self._rgb 
     749        return c.redF(), c.greenF(), c.blueF(), c.alphaF() 
     750    def _set_rgba(self, values): 
     751        values = self._normalizeList(values) 
     752        r, g, b, a = values 
     753        self._rgb.setRgbF(r, g, b, a) 
     754    rgba = property(_get_rgba, _set_rgba, doc="the red, green, blue and alpha values of the color") 
     755 
     756    def _get_cyan(self): 
     757        return self._rgb.cyanF() 
     758    def _set_cyan(self, val): 
     759        val = self._normalize(val) 
     760        c, m, y, k, a = self.cmyka 
     761        self._rgb.setCmykF(val, m, y, k, a) 
     762        self._updateRgb()         
     763    c = cyan = property(_get_cyan, _set_cyan, doc="the cyan component of the color") 
     764 
     765    def _get_magenta(self): 
     766        return self._rgb.magentaF() 
     767    def _set_magenta(self, val): 
     768        val = self._normalize(val) 
     769        c, m, y, k, a = self.cmyka 
     770        self._rgb.setCmykF(c, val, y, k, a) 
     771        self._updateRgb()         
     772    m = magenta = property(_get_magenta, _set_magenta, doc="the magenta component of the color") 
     773 
     774    def _get_yellow(self): 
     775        return self._rgb.yellowF() 
     776    def _set_yellow(self, val): 
     777        val = self._normalize(val) 
     778        c, m, y, k, a = self.cmyka 
     779        self._rgb.setCmykF(c, m, val, k, a) 
     780        self._updateRgb()         
     781    y = yellow = property(_get_yellow, _set_yellow, doc="the yellow component of the color") 
     782 
     783    def _get_black(self): 
     784        return self._rgb.blackF() 
     785    def _set_black(self, val): 
     786        val = self._normalize(val) 
     787        c, m, y, k, a = self.cmyka 
     788        self._rgb.setCmykF(c, m, y, val, a) 
     789        self._updateRgb()         
     790    k = black = property(_get_black, _set_black, doc="the black component of the color") 
     791 
     792    def _get_cmyka(self): 
     793        c = self._rgb 
     794        return c.cyanF(), c.magentaF(), c.yellowF(), c.blackF(), c.alphaF() 
     795    cmyka = property(_get_cmyka, doc="a tuple containing the CMYKA values for this color") 
    583796 
    584797    def _normalize(self, v): 
     
    604817        elif isinstance(transform, (list, tuple)): 
    605818            matrix = tuple(transform) 
    606             transform = QTransform() 
    607             transform.setMatrix(*matrix) 
     819            transform = QTransform(*matrix) 
    608820        elif isinstance(transform, QTransform): 
    609821            pass 
     
    622834    def concat(self, painter): 
    623835        trans = painter.transform() 
    624         painter.setTransform(trans * self._qtransform) 
     836        painter.setTransform(self._qtransform * trans) 
    625837 
    626838    def copy(self): 
     
    637849    def _get_matrix(self): 
    638850        q = self._qtransform 
    639         return (q.m11(), q.m12(), q.m13(), q.m21(), q.m22(), q.m23(), q.m31(), q.m32(), q.m33()) 
     851        return (q.m11(), q.m12(), q.m21(), q.m22(), q.m31(), q.m32()) 
    640852    def _set_matrix(self, value): 
    641         self._qtransform.setMatrix(value) 
     853        self._qtransform = QTransform(*value) 
    642854    matrix = property(_get_matrix, _set_matrix) 
    643855 
     
    657869 
    658870    def skew(self, x=0, y=0): 
    659         self._qtransform.shear(x, y) 
     871        import math 
     872        x = math.pi * x / 180. 
     873        y = math.pi * y / 180. 
     874        t = Transform() 
     875        t.matrix = 1, math.tan(y), -math.tan(x), 1, 0, 0 
     876        self.prepend(t) 
    660877 
    661878    def invert(self): 
     
    711928        TransformMixin.__init__(self) 
    712929        if data is not None: 
    713             self._nsImage = QImage(data) 
     930            self._qimage = QImage(data) 
    714931            if self._qimage is None: 
    715932                raise NodeBoxError, "can't read image %r" % path 
     
    753970 
    754971    def getSize(self): 
    755         return self._nsImage.size() 
     972        return self._qimage.width(), self._qimage.height() 
    756973 
    757974    size = property(getSize) 
     
    760977        """Draw an image on the given coordinates.""" 
    761978 
    762         srcW, srcH = self._qimage.width(), self._qimage.height() 
     979        srcW, srcH = float(self._qimage.width()), float(self._qimage.height()) 
    763980        srcRect = ((0, 0), (srcW, srcH)) 
    764981 
     
    777994                # This is the hardest case: center-mode transformations with given width or height. 
    778995                # Order is very important in this code. 
    779  
    780996                # Set the position first, before any of the scaling or transformations are done. 
    781997                # Context transformations might change the translation, and we don't want that. 
     
    783999                t.translate(self.x, self.y) 
    7841000                t.concat(painter) 
    785  
     1001                 
    7861002                # 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. 
     1003                # to set the new center of the image according to the scaling factors 
    7881004                srcW = srcW * factor 
    7891005                srcH = srcH * factor 
    790  
    791                 # Move image to newly calculated center. 
     1006                 
     1007                # Move image to newly calculated center.                 
    7921008                dX = srcW / 2 
    7931009                dY = srcH / 2 
     
    7991015                self._transform.concat(painter) 
    8001016 
    801                 # Move back to the previous position. 
     1017                # Move back to the previous position.                 
    8021018                t = Transform() 
    8031019                t.translate(-dX, -dY) 
    8041020                t.concat(painter) 
    8051021 
    806                 # Finally, scale the image according to the factors. 
     1022                # Finally, scale the image according to the factors.                 
    8071023                t = Transform() 
    8081024                t.scale(factor) 
    809                 t.concat(painter) 
     1025                t.concat(painter)           
    8101026            else: 
    8111027                # Do current transformation 
    812                 #self._transform.concat() 
     1028                self._transform.concat(painter) 
    8131029                # Scale according to width or height factor 
    8141030                t = Transform() 
     
    8191035            # A debugImage draws a black rectangle instead of an image. 
    8201036            if self.debugImage: 
    821                 painter.setBrush(QBrush(Qt.SolidPattern)) 
    822                 painter.fillRect(QRectF(0, 0, srcW / factor, srcH / factor)) 
     1037                painter.setBrush(QBrush(Qt.black)) 
     1038                painter.setPen(QPen(Qt.NoPen)) 
     1039                painter.drawRect(QRectF(0, 0, srcW / factor, srcH / factor)) 
    8231040            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)) 
     1041                painter.setOpacity(self.alpha) 
     1042                painter.drawImage(0, 0, self._qimage) 
    8261043            painter.restore() 
    8271044        # No width or height given 
     
    8421059            # A debugImage draws a black rectangle instead of an image. 
    8431060            if self.debugImage: 
    844                 painter.setBrush(QBrush(Qt.SolidPattern)) 
    845                 painter.fillRect(QRectF(0, 0, srcW, srcH)) 
     1061                painter.setBrush(QBrush(Qt.black)) 
     1062                painter.setPen(QPen(Qt.NoPen)) 
     1063                painter.drawRect(QRectF(x, y, srcW, srcH)) 
    8461064            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)) 
     1065                t = Transform() 
     1066                t.translate(x, y) 
     1067                t.concat(painter) 
     1068                painter.setOpacity(self.alpha) 
     1069                painter.drawImage(0, 0, self._qimage) 
    8491070            painter.restore() 
    8501071 
     
    8551076 
    8561077    __dummy_color = QColor() 
    857     __alignMap = { LEFT: Qt.AlignLeft, RIGHT: Qt.AlignRight, CENTER: Qt.AlignCenter, JUSTIFY: Qt.AlignJustify } 
     1078    __alignMap = { LEFT: Qt.AlignLeft, RIGHT: Qt.AlignRight, CENTER: Qt.AlignHCenter, JUSTIFY: Qt.AlignJustify } 
    8581079     
    8591080    def __init__(self, ctx, text, x=0, y=0, width=None, height=None, **kwargs): 
     
    8851106 
    8861107    def _get_font(self): 
    887         return QFont(self._fontname, self._fontsize) 
     1108        f = QFont(self._fontname) 
     1109        f.setPointSizeF(self._fontsize / textScaleFactor) 
     1110        return f 
    8881111    _qfont = property(_get_font) 
    8891112 
    8901113    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  
    9031114        if self._fillcolor is None: return 
    904         x,y = r.x(), r.y() 
     1115        flags = self.__alignMap[self._align] | Qt.TextWordWrap 
     1116        fm = QFontMetricsF(self._qfont)                 
     1117        w = self.width or 100000 
     1118        h = self.height or 100000 
     1119        preferredWidth, preferredHeight = w, h 
     1120        r = fm.boundingRect(QRectF(self.x, self.y, w, h), flags, self.text) 
     1121        x, y = r.x(), r.y() 
    9051122        w, h = r.width(), r.height() 
    906         preferredWidth, preferredHeight = r.width(), r.height() 
    9071123        if self.width is not None: 
    9081124            if self._align == RIGHT: 
     
    9111127                x += preferredWidth/2 - w/2 
    9121128 
     1129        textLayout = QTextLayout() 
     1130        textLayout.setFont(self._qfont) 
     1131        textLayout.setText(self.text) 
     1132        opt = QTextOption() 
     1133        opt.setAlignment(self.__alignMap[self._align]) 
     1134        opt.setWrapMode(QTextOption.WrapAtWordBoundaryOrAnywhere) 
     1135        textLayout.setTextOption(opt) 
     1136        textLayout.beginLayout() 
     1137        lineSpacing = (fm.ascent() + fm.descent() + fm.leading()) * self._lineheight 
     1138 
     1139        advance = 0 
     1140        while True: 
     1141            line = textLayout.createLine() 
     1142            if not line.isValid(): 
     1143                break 
     1144            line.setLineWidth(w) 
     1145            line.setPosition(QPointF(0, advance)) 
     1146            advance += lineSpacing 
     1147        textLayout.endLayout() 
     1148         
    9131149        painter.save() 
    914         painter.setFont(self._qfont) 
    915         self._fillcolor._set(painter) 
    916         #painter.setBrush(QBrush(self._fillcolor)) 
     1150        p = QPen(QBrush(self._fillcolor._rgb), 0) 
     1151        painter.setPen(p) 
     1152         
    9171153        # Center-mode transforms: translate to image center 
    9181154        if self._transformmode == CENTER: 
     1155            lc = textLayout.lineCount()*lineSpacing 
    9191156            deltaX = w / 2 
    9201157            deltaY = h / 2 
    9211158            t = Transform() 
    922             #t.translate(x+deltaX, y+fm.ascent()+deltaY) 
     1159            t.translate(deltaX,lc/2) 
    9231160            t.concat(painter) 
    9241161            self._transform.concat(painter) 
    925             painter.drawText(x, y, w, h, flags, self.text) 
    926             #layoutManager.drawGlyphsForGlyphRange_atPoint_(glyphRange, (-deltaX-dx,-deltaY-dy)) 
     1162            t = Transform() 
     1163            t.translate(-deltaX,-lc/2) 
     1164            t.concat(painter) 
    9271165        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())) 
     1166            self._transform.concat(painter) 
     1167 
     1168        textLayout.draw(painter, QPointF(x, y)) 
    9311169        painter.restore() 
    9321170        return (w, h) 
     
    9341172    def _get_metrics(self): 
    9351173        # 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) 
     1174        flags = self.__alignMap[self._align] | Qt.TextWordWrap 
     1175        fm = QFontMetricsF(self._qfont) 
     1176        w = self.width or 100000 
     1177        h = self.height or 100000 
     1178        r = fm.boundingRect(QRectF(self.x, self.y, w, h), flags, self.text) 
    9491179        return r.width(), r.height() 
    9501180    metrics = property(_get_metrics) 
     
    10591289            raise NodeBoxError, "pop: too many canvas pops!" 
    10601290 
     1291    def _setTextScaleFactor(self, factor): 
     1292        global textScaleFactor 
     1293        textScaleFactor = factor 
     1294         
    10611295    def draw(self, painter): 
    10621296        if self.background is not None: 
     1297            painter.save() 
    10631298            painter.fillRect(0,0, self.width, self.height, self.background._rgb) 
     1299            painter.restore() 
    10641300        for grob in self._grobs: 
    10651301            grob._draw(painter) 
     
    10731309            svgGen.setFileName(fname) 
    10741310            svgGen.setSize(QSize(self.width, self.height)) 
    1075             painter = QPainter(svgGen) 
     1311            painter = QPainter() 
     1312            painter.begin(svgGen) 
    10761313            self.draw(painter) 
    10771314            painter.end() 
     
    10811318            printer.setOutputFileName(fname) 
    10821319            printer.setFullPage(True) 
    1083             #printer.setPageSize(QPrinter.Custom) 
    1084             painter = QPainter(printer) 
     1320            printer.setPaperSize(QSizeF(self.width, self.height), QPrinter.Point) 
     1321            painter = QPainter() 
     1322            painter.begin(printer) 
    10851323            self.draw(painter) 
    10861324            painter.end() 
    10871325        elif format in ("png", "tiff", "jpg", "jpeg"): 
    10881326            img = QImage(self.width, self.height, QImage.Format_ARGB32) 
    1089             painter = QPainter(img) 
    1090             painter.setRenderHints(QPainter.Antialiasing | QPainter.TextAntialiasing) 
     1327            painter = QPainter() 
     1328            painter.begin(img) 
     1329            painter.setRenderHints(QPainter.Antialiasing | QPainter.TextAntialiasing | QPainter.SmoothPixmapTransform) 
     1330            if format in ("jpg", "jpeg"): 
     1331                painter.fillRect(0, 0, self.width, self.height, Qt.white) 
    10911332            self.draw(painter) 
    10921333            painter.end() 
  • nodebox/branches/try-qt-painter/nodebox/gui/qt/__init__.py

    r286 r484  
    77import random 
    88 
    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 
     9from 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 
     10from PyQt4.QtCore import Qt, SIGNAL, SLOT, pyqtSignature, QTimer, QRectF, QSize, QCoreApplication, QSettings, QVariant, QPoint 
    1111from PyQt4.QtSvg import QSvgGenerator 
    12  
    13 from nodebox.gui.qt.editor import PythonHighlighter, CodeEdit, loadConfig 
     12from PyQt4.QtOpenGL import QGLWidget, QGLFormat, QGL 
     13 
     14from nodebox.gui.qt.ValueLadder import MAGICVAR 
     15from nodebox.gui.qt.pytextview import PythonHighlighter, PyTextView, loadConfig, Config 
     16from nodebox.gui.qt.dashboard import DashboardController 
    1417 
    1518MAGICVAR = "__magic_var__" 
     
    3235        self.data.append((self.isErr, data)) 
    3336 
    34 class NodeBoxGraphicsView(QWidget): 
    35  
    36     def __init__(self, parent=None): 
    37         QWidget.__init__(self, parent) 
    38         self.setMinimumSize(300, 300) 
     37class NodeBoxGraphicsView(): 
     38    zoomLevels = [0.1, 0.25, 0.5, 0.75] 
     39    zoom = 1.0 
     40    while zoom <= 20.0: 
     41        zoomLevels.append(zoom) 
     42        zoom += 1.0 
     43 
     44    def __init__(self): 
    3945        self._canvas = None 
    4046        self._image = None 
    4147        self._dirty = True 
    42          
     48        self._zoom = 1.0 
     49        self._mouseDown = False 
     50         
     51    def mousePressEvent(self, event): 
     52        if event.button() == Qt.LeftButton: 
     53            self._mouseDown = True 
     54 
     55    def mouseReleaseEvent(self, event): 
     56        if event.button() == Qt.LeftButton: 
     57            self._mouseDown = False 
     58 
     59    def mousePosition(self): 
     60        pos = self.mapFromGlobal(QCursor.pos()) 
     61        return QPoint(pos.x(), pos.y()) 
     62 
    4363    def _get_canvas(self): 
    4464        return self._canvas 
    4565    def _set_canvas(self, canvas): 
    4666        self._canvas = canvas 
    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) 
    5072        self.markDirty() 
    5173    canvas = property(_get_canvas, _set_canvas) 
    5274         
     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 
    53129    def markDirty(self, redraw=True): 
    54130        self._dirty = True 
     
    59135        self._image = None 
    60136        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)) 
     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) 
    65144        try: 
     145            p.save() 
    66146            self.canvas.draw(p) 
    67147        except: 
     
    76156            outputView.insertPlainText(data) 
    77157        finally: 
     158            p.restore() 
    78159            p.end() # TODO: This doesn't fix the QWidget warning if error happens during drawing. 
    79         self._image = img 
    80160         
    81161    def paintEvent(self, event): 
    82         p = QPainter(self) 
    83         p.setRenderHints(QPainter.Antialiasing | QPainter.TextAntialiasing) 
    84162        if self.canvas is None: 
     163            p = QPainter(self) 
    85164            p.fillRect(0, 0, self.width(), self.height(), QColor(Qt.white)) 
    86165        else: 
    87166            if self._dirty: 
    88167                self._updateImage() 
    89             p.drawPixmap(0, 0, self._image) 
    90          
     168 
     169class QGLNodeBoxGraphicsView(QGLWidget, NodeBoxGraphicsView): 
     170    def __init__(self, parent=None): 
     171        QGLWidget.__init__(self, QGLFormat(QGL.SampleBuffers | QGL.AlphaChannel), parent) 
     172        NodeBoxGraphicsView.__init__(self) 
     173         
     174class QNodeBoxGraphicsView(QWidget, NodeBoxGraphicsView): 
     175    def __init__(self, parent=None): 
     176        QWidget.__init__(self, parent) 
     177        NodeBoxGraphicsView.__init__(self) 
     178 
    91179class NodeBoxDocument(QMainWindow): 
    92180    def __init__(self): 
     
    98186        self.namespace = {} 
    99187        self.canvas = graphics.Canvas() 
     188        textScaleFactor = QPixmap().logicalDpiX() / 72.0 
     189        self.canvas._setTextScaleFactor(textScaleFactor) 
    100190        self.context = graphics.Context(self.canvas, self.namespace) 
    101191        self.animationTimer = None 
     
    110200 
    111201    def createMenu(self): 
    112         #self.menuBar = QMenuBar() 
    113  
    114202        self.fileMenu = QMenu(self.tr("&File"), self) 
    115203        self.fileMenu.addAction(self.tr("&New"), self, SLOT("doNew()"), QKeySequence("Ctrl+N")) 
     
    136224        self.menuBar().addMenu(self.editMenu) 
    137225 
     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 
    138239        self.pythonMenu = QMenu(self.tr("&Python"), self) 
    139240        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+.")) 
     241        self.runAction = self.pythonMenu.addAction(self.tr("&Stop"), self, SLOT("doStop()"), QKeySequence("Ctrl+B")) 
    141242        self.menuBar().addMenu(self.pythonMenu) 
    142243 
     
    163264        codeFormat = QTextCharFormat() 
    164265        codeFormat.setFont(codeFont) 
    165          
    166         self.graphicsView = NodeBoxGraphicsView() 
     266 
     267        global app 
     268        self.graphicsView = app._NodeBoxGraphicsView(self) 
    167269        self.graphicsView.document = self 
    168270        self.graphicsView.resize(1000, 1000) 
    169271        self.graphicsScroll = QScrollArea() 
    170272        self.graphicsScroll.setWidget(self.graphicsView) 
    171         self.graphicsScroll.setMinimumSize(300, 300) 
    172         self.codeView = CodeEdit() 
     273        self.graphicsScroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn) 
     274        self.graphicsScroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) 
     275        self.codeView = PyTextView() 
     276        self.codeView._document = self 
    173277        self.codeView.setFontFamily(codeFont.defaultFamily()) 
    174278        self.codeView.setCurrentFont(codeFont) 
     
    176280        self.codeView.setMinimumSize(300, 300) 
    177281        self.codeView.setAcceptRichText(False) 
     282        self.codeView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn) 
     283        self.codeView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) 
    178284        PythonHighlighter(self.codeView.document()) 
    179285        self.outputView = QTextEdit() 
     
    184290        self.outputView.setAcceptRichText(False) 
    185291        self.outputView.setReadOnly(True) 
     292        self.outputView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) 
    186293         
    187294        self.code_errors = QSplitter(Qt.Vertical) 
     
    189296        self.code_errors.addWidget(self.outputView) 
    190297 
     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 
    191336        self.view_edit = QSplitter() 
    192         self.view_edit.addWidget(self.graphicsScroll) 
     337        self.view_edit.addWidget(self.graphics_zoom) 
    193338        self.view_edit.addWidget(self.code_errors) 
    194339        self.view_edit.setObjectName("view_edit") 
    195         self.view_edit.setStyleSheet("QSplitter#view_edit { margin: 10px 10px 20px 10px; border: 0 }") 
     340        self.view_edit.setStyleSheet("#view_edit { margin: 10px 10px 20px 10px; border: 0 }") 
    196341        l = QGridLayout() 
    197342        l.setHorizontalSpacing(10) 
    198343        l.setVerticalSpacing(10) 
    199344        self.view_edit.setLayout(l) 
    200          
    201         #self.centralWidget = QWidget() 
    202         #self.centralWidget.addWidget(self.view_edit) 
    203         #self.centralWidget.setLayout(QGridLayout()) 
    204          
    205345        self.setCentralWidget(self.view_edit) 
    206346        self.setUnifiedTitleAndToolBarOnMac(True) 
     
    208348 
    209349        self.setWindowTitle(self.tr("Untitled")) 
     350        self.dashboardController = DashboardController(self) 
    210351        self.resize(800, 600) 
    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 
    212398    @pyqtSignature("") 
    213399    def doNew(self): 
     
    279465 
    280466    @pyqtSignature("") 
     467    def doExportAsMovie(self): 
     468        pass 
     469 
     470    @pyqtSignature("") 
     471    def doPrint(self): 
     472        pass 
     473 
     474    @pyqtSignature("") 
    281475    def doRun(self): 
    282476        if self.fullScreen is not None: return 
     
    317511    fileName = property(_get_fileName, _set_fileName) 
    318512 
     513    def buildInterface_(self): 
     514        if not self.dashboardController: 
     515            self.dashboardController = DashboardController(self) 
     516        self.dashboardController.buildInterface_(self.vars) 
     517 
    319518    def _runScript(self, compile=True, newSeed=True): 
    320         if not self.cleanRun(self._execScript): 
     519        if not self.cleanRun(self._execScript, newSeed): 
    321520            pass 
    322521 
     
    337536            if self.namespace.has_key("setup"): 
    338537                self.fastRun(self.namespace["setup"]) 
    339             window = self.currentView.window() 
     538#            window = self.currentView.window() 
    340539            #window.makeFirstResponder_(self.currentView) 
    341540 
     
    344543            self.connect(self.animationTimer, SIGNAL("timeout()"), self, SLOT("doFrame()")) 
    345544            self.animationTimer.start(1000.0 / self.speed) 
    346  
     545             
    347546    def runScriptFast_(self):         
    348547        if self.animationTimer is None: 
     
    365564            # Build the interface 
    366565            self.vars = self.namespace["_ctx"]._vars 
    367             if len(self.vars) > 0: 
     566            if newSeed and len(self.vars) > 0: 
    368567                self.buildInterface_() 
    369568 
     
    406605 
    407606        # 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 
     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             
    416616        self.namespace["MOUSEX"], self.namespace["MOUSEY"] = mx, my 
    417         #self.namespace["mousedown"] = QApplication.mouseButtons() & Qt.LeftButton 
     617        self.namespace["mousedown"] = self.currentView._mouseDown 
    418618        #self.namespace["keydown"] = self.currentView.keydown 
    419619        #self.namespace["key"] = self.currentView.key 
     
    563763class FullscreenView(QDialog): 
    564764    pass 
     765 
     766def 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() 
    565789     
    566790class NodeBoxApplication(QApplication): 
     
    572796        self.settings = QSettings() 
    573797        loadConfig() 
     798        overrideConfig(self) 
    574799        self.documents = [] 
    575800        if sys.platform == "win32": 
     
    591816        except OSError: pass 
    592817        except IOError: pass 
     818        import nodebox.gui 
     819        dir_gui = nodebox.gui.__file__ 
     820        self.dir_gui = os.path.split(os.path.realpath(dir_gui))[0] 
     821        if '-gl' in args: 
     822            self._NodeBoxGraphicsView = QGLNodeBoxGraphicsView 
     823        else:             
     824            self._NodeBoxGraphicsView = QNodeBoxGraphicsView 
    593825             
    594826    def newDocument(self):