Commits

Brendan Howell committed cc96d4d Merge
  • Participants
  • Parent commits fa098e6, b3efc43

Comments (0)

Files changed (14)

File drawing_cairo.py

 """
     drawing.py
-    Copyright 2009 Brendan Howell (brendan@howell-ersatz.com)
+    Copyright 2012 Brendan Howell (brendan@howell-ersatz.com)
 
     This file is part of PyCessing.
 
 
 import pygame
 import cairo
+import pangocairo
+import pango
 import numpy
 import math
-import Image
+#import Image
 import array
 
-#TODO: could add filters since we are now using PIL
-
-def bgra_surf_to_rgba_string(cairo_surface):
-    # use PIL to do this
-    img = Image.frombuffer(
-        'RGBA', (cairo_surface.get_width(),
-                 cairo_surface.get_height()),
-        cairo_surface.get_data(), 'raw', 'BGRA', 0, 1)
- 
-    return img.tostring('raw', 'RGBA', 0, 1)
 
 class Drawing:
     def __init__(self):
         self.fill = True
         self.fill_color = (0.5, 0, 0.5, 1)
         
-    #TODO: see if this can be optimized and just grab the context every time
+    #grab the context at the beginning of the frame
     def setSurface(self, sdl_surface):
         self.sdl_surface = sdl_surface
         width = sdl_surface.get_width()
         height = sdl_surface.get_height()
         
-        stride = width * 4
-        #pixels = pygame.surfarray.pixels2d(sdl_surface)
-        #self.surface = cairo.ImageSurface.create_for_data(bytes, cairo.FORMAT_RGBA32, width, height)
-        #self.data = numpy.empty(width * height * 4, dtype=numpy.int8)
-        self.data = array.array("c",chr(0) * width * height * 4)
-        self.surface = cairo.ImageSurface.create_for_data(self.data, cairo.FORMAT_ARGB32, width, height, stride)
-        #self.surface = cairo.ImageSurface.create_for_data(sdl_surface.get_buffer(), cairo.FORMAT_RGB24, width, height, stride)
+        self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
         self.ctx = cairo.Context(self.surface)
+        self.pangoctx = pangocairo.CairoContext(self.ctx)
+        self.font_map = pangocairo.cairo_font_map_get_default()
+        self.families = self.font_map.list_families()
         
     def setBackground(self, red, green, blue):
-        self.setSurface(self.sdl_surface)
         self.ctx.set_source_rgba(blue/255.0, green/255.0, red/255.0, 1)
-        #self.ctx.set_source_rgba(0.4, 0.4, 0.4, 1)
         self.ctx.paint()
-        #self.surface.finish()
-        self._blitToScreen()
-        #self.sdl_surface.fill((red, green, blue))
         
     def setStroke(self, red, green, blue, alpha=255, width=1):
         self.setStrokeWidth(width)
         self.fill = fill
         
     def rect(self, x, y, width, height): 
-        self.setSurface(self.sdl_surface)
         self.ctx.rectangle(x, y, width, height)
         self._fillAndStroke()
     
     def circle(self, cx, cy, radius):
-        self.setSurface(self.sdl_surface)
         self.ctx.arc(cx, cy, radius, 0, 2.0 * math.pi)
         self._fillAndStroke()
     
     def ellipse(self, cx, cy, width, height):
-        self.setSurface(self.sdl_surface)
         self.ctx.save()
         self.ctx.translate(cx, cy)
         self.ctx.scale(width / 2.0, height / 2.0)
         self._fillAndStroke()
     
     def arc(self, cx, cy, radius, startAngle, endAngle):
-        self.setSurface(self.sdl_surface)
         self.ctx.arc(cx, cy, radius, math.radians(startAngle), math.radians(endAngle))
         self._fillAndStroke()
         
     def line(self, x1, y1, x2, y2):
-        self.setSurface(self.sdl_surface)
         self.ctx.move_to(x1, y1)
         self.ctx.line_to(x2, y2)
         self._fillAndStroke()
     
     def polygon(self, pointlist):
-        self.setSurface(self.sdl_surface)
         x, y = pointlist[0]
         self.ctx.move_to(x, y)
         for point in pointlist[1:]:
         self._fillAndStroke()
                 
     def curve(self, x1, y1, cx1, cy1, cx2, cy2, x2, y2):
-        self.setSurface(self.sdl_surface)
         self.ctx.move_to(x1, y1)
         self.ctx.curve_to(cx1, cy1, cx2, cy2, x2, y2)
         self._fillAndStroke()
 
     def screenGrab(self, fileName):
-	pygame.image.save(self.sdl_surface, fileName)
+        pygame.image.save(self.sdl_surface, fileName)
+        
+    def drawText(self, x, y, txt):
+        self.ctx.save()
+        self.ctx.translate(x,y)
+        self.ctx.set_source_rgb(0, 0, 0)
+        layout = self.pangoctx.create_layout()
+        #print dir(self.families[0])
+        print self.families[0].get_name()
+        layout.set_font_description(pango.FontDescription(self.families[0].get_name() + " 25"))
+        layout.set_width(300)
+        layout.set_text(txt)
+        self.pangoctx.update_layout(layout)
+        print('ctx.POS: %s %s'%self.ctx.get_current_point())
+        self.pangoctx.show_layout(layout)
+        print('F => %s %s'%layout.get_pixel_size())
+        self.ctx.restore()
         
     def _fillAndStroke(self):
         if(self.fill):
             self.ctx.stroke()
         else:
             self.ctx.new_path()
-        #self.surface.finish()
-        self._blitToScreen()
-        
+
+    #TODO: finish this
     def renderToPDF(self, fileName):
     	self.surface = cairo.PDFSurface(fileName, self.sdl_surface.get_width(), self.sdl_surface.get_height())
     	
-    	#
-    	
-    	
-        
-    def _blitToScreen(self):
-        #data_string = bgra_surf_to_rgba_string(self.surface)
-        blue = self.data[0::4]
-        red = self.data[2::4]
-        self.data[0::4] = red 
-        self.data[2::4] = blue
-        pygame_surface = pygame.image.frombuffer(self.data.tostring(), 
-                (self.sdl_surface.get_width(), 
-                 self.sdl_surface.get_height()
-                ), 
-                'RGBA')
-        self.sdl_surface.unlock()
-        self.sdl_surface.blit(pygame_surface, (0,0))        
+
+    def _blitToScreen(self):  
+        dest = pygame.surfarray.pixels2d(self.sdl_surface)
+        dest.data[:] = self.surface.get_data()
     	

File examples/wrappingpaper-cir.jpg

Old
Old image
New
New image

File help/core-function-index.html

 <html>
 <head>
   <title>Pycessing Documentation</title>
+  
+  <link rel="stylesheet" media="screen" href="media/css/style.css" />
 </head>
 <body>
 <h1>PyCessing Object and Function Reference</h1>
 <ul>
     <li>Forms and Shapes</li>
     <ul>
-	    <li><a href="drawing.html#circle">circle()</a></li>
-	    <li><a href="drawing.html#rect">rect()</a></li>
-	    <li><a href="drawing.html#ellipse">ellipse()</a></li>
+	    <li><a href="drawing-circle.html">circle()</a></li>
+	    <li><a href="drawing-rect.html">rect()</a></li>
+	    <li><a href="drawing-ellipse.html">ellipse()</a></li>
 	    <li><a href="drawing.html#arc">arc()</a></li>
 	    <li><a href="drawing.html#line">line()</a></li>
 	    <li><a href="drawing.html#polygon">polygon()</a></li>

File help/drawing-circle.html

+<html>
+<head>
+  <title>Pycessing Documentation</title>
+  <link rel="stylesheet" media="screen" href="media/css/style.css" />
+</head>
+<body>
+
+<h1>PyCessing Object and Function Reference</h1>
+<h4><a href="core-function-index.html">Back to full reference</a></h4>
+
+<h2>Forms & Shapes: <strong>circle ()</strong></h2>
+
+<p><strong>Sintax</strong></p>
+<code>
+  <pre>circle( x, y, radius )</pre>
+</code>
+
+<p><strong>Description</strong></p>
+<p>Draws a circle in the display window.</p>
+
+<p><strong>Example</strong></p>
+<p>
+  <img src="media/examples/circle.png" alt="Circle"/>
+</p>
+<code>
+  <pre>
+  setFillColor(255, 255, 255)
+  circle (150, 100, 35)</pre>
+</code>
+
+
+<p>
+  <strong>Related</strong>
+  <a href="drawing-ellipse.html">ellipse()</a>
+</p>
+
+<h4><a href="core-function-index.html">Back to full reference</a></h4>

File help/drawing-ellipse.html

+<html>
+<head>
+  <title>Pycessing Documentation</title>
+  <link rel="stylesheet" media="screen" href="media/css/style.css" />
+</head>
+<body>
+
+<h1>PyCessing Object and Function Reference</h1>
+<h4><a href="core-function-index.html">Back to full reference</a></h4>
+
+<h2>Forms & Shapes: <strong>ellipse ()</strong></h2>
+
+<p><strong>Sintax</strong></p>
+<code>
+  <pre>ellipse( x, y, width, height )</pre>
+</code>
+
+<p><strong>Description</strong></p>
+<p>Draws an ellipse in the display window. The first two parameters define the origin, from top left, the second two define the width and height.</p>
+
+<p><strong>Example</strong></p>
+<p>
+  <img src="media/examples/ellipse.png" alt="Ellipse"/>
+</p>
+<code>
+  <pre>
+  setBackground(204, 204, 204)	
+  setFillColor(80, 80, 80)
+  ellipse (80, 80, 60, 100)</pre>
+</code>
+
+
+<p>
+  <strong>Related</strong>
+  <a href="drawing-ellipse.html">circle()</a>
+</p>
+
+<h4><a href="core-function-index.html">Back to full reference</a></h4>

File help/drawing-rect.html

+<html>
+<head>
+  <title>Pycessing Documentation</title>
+  <link rel="stylesheet" media="screen" href="media/css/style.css" />
+</head>
+<body>
+
+<h1>PyCessing Object and Function Reference</h1>
+<h4><a href="core-function-index.html">Back to full reference</a></h4>
+
+<h2>Forms & Shapes: <strong>rect ()</strong></h2>
+
+<p><strong>Sintax</strong></p>
+<code>
+  <pre>rect( x, y, width, heigh )</pre>
+</code>
+
+<p><strong>Description</strong></p>
+<p>Draws an ellipse in the display window. The first two parameters define the origin, from top left, the second two define the width and height.</p>
+
+<p><strong>Example</strong></p>
+<p>
+  <img src="media/examples/rect.png" alt="Rect"/>
+</p>
+<code>
+  <pre>
+  setBackground(204, 204, 204)	
+  setFillColor(80, 80, 80)
+  rect(40, 40, 60, 60)</pre>
+</code>
+
+
+<h4><a href="core-function-index.html">Back to full reference</a></h4>

File help/index.html

 <html>
 <head>
   <title>Pycessing Documentation</title>
+  <link rel="stylesheet" media="screen" href="media/css/style.css" />
 </head>
 <body>
 <h1>PyCessing Documentation</h1>
 <ul>
   <li><a href="core-function-index.html">Object/Function Reference</a></li>
   <li>Tips, Tricks and Tutorials (not done)</li>
-  <li><a href="http://pycessing.org/forum">Forum (online)</a></li>
-  <li><a href="http://pycessing.org/gallery">Project Gallery (online)</a></li>
+  <li><a href="http://pycessing.org/forums">Forum (online)</a></li>
+  <li><a href="http://pycessing.org/project-gallery/">Project Gallery (online)</a></li>
 </ul>
 Welcome to the built-in documentation for PyCessing.  If you are brand new to Python and PyCessing, you may want to start with the Tips, Tricks and Tutorials.  The truly impatient can just to straight to the examples that can be found under File -> Examples.  You can look up any function in the editor by right clicking and selecting "Show Function/Object Help".  "Search on Pycessing.org" will try to find usefule references to the selected code on the PyCessing web site.  
 </body>

File help/media/css/style.css

+/*---------------------------------------------------
+General
+---------------------------------------------------*/
+
+html {
+  height: 100%;
+}
+
+body {
+  font-family: Georgia, Times, serif;
+	font-size: 1em;
+	line-height: 1.4;
+  color: #666;
+  position: relative;
+	height: 100%;
+}
+
+/*---------------------------------------------------
+Typography
+---------------------------------------------------*/
+
+h1, h2, h3, h4, h5, h6 {
+  font-family: 'DejaVu Sans', Helvetica, Arial, sans-serif;
+}
+
+pre {
+	font-family: 'Droid mono', Courier, monospace;
+	font-size: 12px;
+	line-height: 1.4;
+}
+
+
+/*---------------------------------------------------
+Content
+---------------------------------------------------*/
+
+pre {
+	background: #f7f7f7;
+	color: #222;
+	margin: 5px 0 10px;
+	padding: 5px;
+}
+
+
+

File help/media/examples/circle.png

Added
New image

File help/media/examples/ellipse.png

Added
New image

File help/media/examples/rect.png

Added
New image

File mainwindow.py

 #TODO: handle file dirty in header
 #TODO: cut and paste from help browser
 
-from PyQt4 import QtGui, QtCore, Qsci
+from PyQt4 import QtGui, QtCore, Qsci, QtWebKit
 import os, subprocess, signal, tempfile, sys, glob
-from pkg_resources import resource_string, resource_stream, resource_listdir
+from pkg_resources import resource_string, resource_stream, resource_listdir, resource_filename
 
 class MainWindow(QtGui.QMainWindow):
     def __init__(self):
         return True
         
     def openFile(self):
-    	if not(self.newFile()):
-    	    return
+        if not(self.newFile()):
+            return
         self.fileName = QtGui.QFileDialog.getOpenFileName(self, "Open File", "", "Pycessing Files (*.cess)")
         if(self.fileName):
             newFile = open(self.fileName)
         self.textEdit.setText(examplecode)
         self.setWindowTitle('PyCessing - ' + filename)
             
+    #TODO: load front from file if needed
     def setupEditor(self):
         font = QtGui.QFont()
         font.setFamily("Droid Sans Mono")
         
         self.textEdit.setEdgeMode(Qsci.QsciScintilla.EdgeLine)
         self.textEdit.setEdgeColumn(80)
-        self.textEdit.setWrapMode(Qsci.QsciScintilla.WrapWord)
-        self.textEdit.setWrapVisualFlags(Qsci.QsciScintilla.WrapFlagByText)
+        self.textEdit.setWrapMode(Qsci.QsciScintilla.WrapNone)
         self.textEdit.setBraceMatching(Qsci.QsciScintilla.SloppyBraceMatch)
         
         self.splitter.addWidget(self.textEdit)
         size = self.textEdit.sizeHint()
+        size.setWidth(80)
         if size.height() < 300:
             size.setHeight(300)
         print "size: " + str(size.width()) + " x " + str(size.height())
     	#self.messageBox.setAutoFormatting(QtGui.QTextBrowser.LogText)
         
     def setupFileMenu(self):
-        iconfile = os.path.join(self.cwd, 'icons/exit.png')
+        iconfile = resource_filename(__name__,'icons/exit.png')
         exit = QtGui.QAction(QtGui.QIcon(iconfile), '&Quit', self)
         exit.setShortcut('Ctrl+Q')
         exit.setStatusTip('Exit application')
         fileMenu.addAction("&Print", self.printFile, QtGui.QKeySequence("Ctrl+P"))
         fileMenu.addAction(exit)
         
-        exampleDir = os.path.join(self.cwd, 'examples/')
+        exampleDir = resource_filename(__name__,"examples/")
         examples = glob.glob(exampleDir + '*.cess')
         #glob examples
         #TODO: glob sub-directories
 
     def setupToolbar(self):
         toolbar = self.addToolBar('Toolbar')
-        iconfile = os.path.join(self.cwd, 'icons/play.png')
+        iconfile = resource_filename(__name__,'icons/play.png')
         self.playToggle = QtGui.QAction(QtGui.QIcon(iconfile), 'Run Program', toolbar)
         self.connect(self.playToggle, QtCore.SIGNAL('triggered()'), self.togglePlaying)
         toolbar.addAction(self.playToggle)
         #add expandable spacer
         
         # find button
-        iconfile = os.path.join(self.cwd, "icons/Edit-find.png")
+        iconfile = resource_filename(__name__,"icons/Edit-find.png")
         self.findbutton = QtGui.QAction(QtGui.QIcon(iconfile), 'Find in Program', toolbar)
         self.connect(self.findbutton, QtCore.SIGNAL('triggered()'), self.findNext)
         toolbar.addAction(self.findbutton)
 
         #add help browser toggle        
-        iconfile = os.path.join(self.cwd, "icons/help-browser.png")
+        iconfile = resource_filename(__name__,"icons/help-browser.png")
         self.helptoggle = QtGui.QAction(QtGui.QIcon(iconfile), 'Show / Hide Help', toolbar)
         self.connect(self.helptoggle, QtCore.SIGNAL('triggered()'), self.toggleHelpBrowser)
         #help hide / show action
         toolbar.addAction(self.helptoggle)
         
     def setupHelpMenu(self):
-        iconfile = os.path.join(self.cwd, 'icons/about.png')
+        iconfile = resource_filename(__name__,'icons/about.png')
         aboutItem = QtGui.QAction(QtGui.QIcon('icons/about.png'), 'About', self)
         self.connect(aboutItem, QtCore.SIGNAL('triggered()'), self.about)
     
         helpMenu = menubar.addMenu('&Help')
         helpMenu.addAction(aboutItem)
         
-    	self.helpwindow = QtGui.QDockWidget("Doc Browser")
-    	self.helpwindow.setAllowedAreas(QtCore.Qt.RightDockWidgetArea)
-    	self.helpwindow.setMinimumWidth(400)
-    	self.helpwindow.setFeatures(QtGui.QDockWidget.DockWidgetClosable | QtGui.QDockWidget.DockWidgetFloatable)
-    	helpAction = self.helpwindow.toggleViewAction()
-    	helpAction.setText("&Help Browser")
-    	helpAction.setShortcut(QtGui.QKeySequence("F1"))
-    	helpMenu.addAction(helpAction)
-    	self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.helpwindow)
-    	
-    	helpbrowser = QtGui.QTextBrowser(self.helpwindow)
-    	indexpath = os.path.join(self.cwd, "help", "index.html")
-    	url = QtCore.QUrl("file://" + indexpath)
-    	helpbrowser.setSource(url)
-    	helpbrowser.resize(400, self.helpwindow.height())
-    	
+        self.helpwindow = QtGui.QDockWidget("Doc Browser")
+        self.helpwindow.setAllowedAreas(QtCore.Qt.RightDockWidgetArea)
+        self.helpwindow.setMinimumWidth(400)
+        self.helpwindow.setFeatures(QtGui.QDockWidget.DockWidgetClosable | QtGui.QDockWidget.DockWidgetFloatable)
+        helpAction = self.helpwindow.toggleViewAction()
+        helpAction.setText("&Help Browser")
+        helpAction.setShortcut(QtGui.QKeySequence("F1"))
+        helpMenu.addAction(helpAction)
+        self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.helpwindow)
+        
+        helpbrowser = QtWebKit.QWebView(self.helpwindow)
+        indexpath = resource_filename(__name__,"help/index.html")
+        url = QtCore.QUrl("file://" + indexpath)
+        helpbrowser.load(url)
+        helpbrowser.resize(400, self.helpwindow.height())
+        helpbrowser.show()
+        
+##        helpbrowser = QtGui.QTextBrowser(self.helpwindow)
+##        csspath = resource_filename(__name__,"help/media/css/style.css")
+##        csstxt = open(csspath).read()
+##        helpbrowser.document().setDefaultStyleSheet(csstxt)
+##        helpbrowser.setOpenExternalLinks(True)
+##        
+##        indexpath = resource_filename(__name__,"help/index.html")
+##        url = QtCore.QUrl("file://" + indexpath)
+##        helpbrowser.setSource(url)
+##        helpbrowser.resize(400, self.helpwindow.height())
+
         
     def setupEditMenu(self):
         menubar = self.menuBar()
             if self.fileName != None:
                 progdir = os.path.dirname(str(self.fileName))
             else:
-                progdir = os.path.join(self.cwd, 'examples/')
-            args = ["-u", "run.py", self.tempFile, progdir]
+                progdir = resource_filename(__name__,'examples/')
+            run_py = resource_filename(__name__,"run.py")
+            args = ["-u", run_py, self.tempFile, progdir]
             self.sketchPID = QtCore.QProcess(self)
                               
             self.connect(self.sketchPID, QtCore.SIGNAL('finished(int,QProcess::ExitStatus)'), self._progStopped)
             self.sketchPID.waitForStarted()
             
             self.running = True
-            iconfile = os.path.join(self.cwd, 'icons/Process-stop.png')
+            iconfile = resource_filename(__name__,'icons/Process-stop.png')
             self.playToggle.setIcon(QtGui.QIcon(iconfile))
             self.playToggle.setToolTip("Stop running program")
             self.statusBar().showMessage("Program Running...")
         else:
             self.statusBar().showMessage("Oops! Program Crashed")
         self.running = False
-        iconfile = os.path.join(self.cwd, 'icons/play.png')
+        iconfile = resource_filename(__name__,'icons/play.png')
         self.playToggle.setIcon(QtGui.QIcon(iconfile))
         self.playToggle.setToolTip("Run program")
     	
 """
     drawing.py
-    Copyright 2009 Brendan Howell (brendan@howell-ersatz.com)
+    Copyright 2012 Brendan Howell (brendan@howell-ersatz.com)
 
     This file is part of PyCessing.
 
     pycessing.doEvents(pygame.fastevent.get())
     draw()
     pycessing.clock.tick(pycessing.framerate)
+    drawing._blitToScreen()
     pygame.display.flip()
     if(pycessing.noLoop):
         while 1:
 else:
      extra_options = dict(
          entry_points = {
-             'gui_scripts': [ 'pycessing = pycessing' ]
+             'gui_scripts': [ 'pycessing = pycessing:main' ]
          },
          scripts = APP,
          #packages = ["mainwindow.py","run.py"],