In the slightly longer term it might be worth adding images as a particular subset of 2D datasets, especially when we have cool functions for manipulating 2D data... :) But that's a bit non-trivial to do at the moment (what's the x,y scale on an image, for example).
I may have messed something up in the patch because I managed to break my CVS so I merged the changes with the trunk manually :( So if something really obvious is broken that's most likely why...
--"As soon as people come up with a measurable substitute for whatever it is they care about they start treating it as more important than the real thing"
-Boris Zbarsky
? bitmap.diff
? veusz.e3t
? dialogs/__init__.pyc
? dialogs/aboutdialog.pyc
? dialogs/dataeditdialog.pyc
? dialogs/exceptiondialog.pyc
? dialogs/importdialog.pyc
? dialogs/importfits.pyc
? dialogs/reloaddata.pyc
? document/__init__.pyc
? document/commandinterface.pyc
? document/commandinterpreter.pyc
? document/doc.pyc
? document/simpleread.pyc
? setting/__init__.pyc
? setting/collections.pyc
? setting/controls.pyc
? setting/setting.pyc
? setting/settingdb.pyc
? setting/settings.pyc
? utils/__init__.pyc
? utils/fitlm.pyc
? utils/measurement.py
? utils/measurement.pyc
? utils/points.pyc
? utils/pref.pyc
? utils/preftypes.pyc
? utils/textrender.pyc
? utils/utilfuncs.pyc
? utils/version.pyc
? widgets/__init__.pyc
? widgets/axis.pyc
? widgets/axisticks.pyc
? widgets/bitmap.py
? widgets/bitmap.pyc
? widgets/containers.pyc
? widgets/fit.pyc
? widgets/graph.pyc
? widgets/image.pyc
? widgets/key.pyc
? widgets/page.pyc
? widgets/plotters.pyc
? widgets/root.pyc
? widgets/widget.pyc
? widgets/widgetfactory.pyc
? windows/__init__.pyc
? windows/action.pyc
? windows/consolewindow.pyc
? windows/mainwindow.pyc
? windows/plotwindow.pyc
? windows/treeeditwindow.pyc
Index: setting/controls.py
===================================================================
RCS file: /cvs/veusz/veusz/setting/controls.py,v
retrieving revision 1.19
diff -u -r1.19 controls.py
--- setting/controls.py 30 Jun 2005 20:40:09 -0000 1.19
+++ setting/controls.py 22 Jul 2005 22:32:11 -0000
@@ -26,6 +26,7 @@
import qt
import setting
+from utils import measurement
class SettingEdit(qt.QLineEdit):
"""Main control for editing settings which are text."""
@@ -69,7 +70,7 @@
except setting.InvalidType:
self.setPaletteBackgroundColor(qt.QColor('red'))
- def onModified(self, mod):
+ def onModified(self, setting, mod):
"""called when the setting is changed remotely"""
self.setText( self.setting.toText() )
@@ -260,7 +261,7 @@
except setting.InvalidType:
self.edit.setPaletteBackgroundColor(qt.QColor('red'))
- def onModified(self, mod):
+ def onModified(self, setting, mod):
"""called when the setting is changed remotely"""
self.edit.setText( self.setting.toText() )
@@ -290,7 +291,7 @@
"""Emitted when checkbox toggled."""
self.setting.set(state)
- def onModified(self, mod):
+ def onModified(self, setting, mod):
"""called when the setting is changed remotely"""
self.setChecked( self.setting.get() )
@@ -345,7 +346,7 @@
except setting.InvalidType:
self.setPaletteBackgroundColor(qt.QColor('red'))
- def onModified(self, mod):
+ def onModified(self, setting, mod):
"""called when the setting is changed remotely"""
self.setCurrentText( self.setting.toText() )
@@ -390,7 +391,7 @@
except setting.InvalidType:
self.setPaletteBackgroundColor(qt.QColor('red'))
- def onModified(self, mod):
+ def onModified(self, setting, mod):
"""called when the setting is changed remotely"""
self.setText( self.setting.toText() )
@@ -421,11 +422,16 @@
# get rid of non-numeric things from the string
num = self.stripnumre.sub('', text)
- # here are a list of possible different units the user can choose
- # between. should this be in utils?
- newitems = [ num+'pt', num+'cm', num+'mm',
- num+'in', num+'%', '1/'+num ]
+ mainwindow = self.topLevelWidget()
+ #Create a list of the current distance in all possible units
+ newitems = []
+ for unit in measurement.measurementClasses.keys():
+ try:
+ newitems.append(self.setting.convert(mainwindow.painter,unit))
+ except measurement.InvalidType:
+ pass
+
# if we're already in this list, we position the current selection
# to the correct item (up and down keys work properly then)
# spaces are removed to make sure we get sensible matches
@@ -502,4 +508,106 @@
def slotModified(self, modified):
"""Update the list of datasets if the document is modified."""
self.populateEntries()
-
+
+class FilenameSetting(qt.QHBox):
+ """Setting that accepts a filename
+ TODO: Factor out image-specific code
+ make text box a bit more intelligent (strip leading + trailing whitespace)
+ make file not found turn the control invalid"""
+ def __init__(self, setting, parent):
+ qt.QHBox.__init__(self, parent)
+
+ self.setting = setting
+ self.edit = qt.QLineEdit(self)
+ b = self.button = qt.QPushButton('Browse...', self)
+
+ self.bgcolour = self.paletteBackgroundColor()
+
+ # set the text of the widget to the
+ self.edit.setText( setting.toText() )
+
+ self.connect(self.edit, qt.SIGNAL('returnPressed()'),
+ self.validateAndSet)
+ self.connect(self.edit, qt.SIGNAL('lostFocus()'),
+ self.validateAndSet)
+ self.connect(b, qt.SIGNAL('clicked()'),
+ self.browseFile)
+
+ self.setting.setOnModified(self.onModified)
+
+ if setting.readonly:
+ self.edit.setReadOnly(True)
+
+ def done(self):
+ """Delete modification notification."""
+ self.setting.removeOnModified(self.onModified)
+
+ def focusOutEvent(self, *args):
+ """Allows us to check the contents of the widget."""
+ qt.QTextEdit.focusOutEvent(self.edit, *args)
+
+ text = unicode(self.text())
+ try:
+ val = self.setting.fromText(text)
+ self.edit.setPaletteBackgroundColor(self.bgcolour)
+
+ # value has changed
+ if self.setting.get() != val:
+ self.setting.set(val)
+
+ except setting.InvalidType:
+ self.edit.setPaletteBackgroundColor(qt.QColor('red'))
+
+ def onModified(self, setting, mod):
+ """called when the setting is changed remotely"""
+ self.edit.setText( self.setting.toText() )
+
+ def browseFile(self):
+ mainwindow = self.topLevelWidget()
+ if mainwindow.bitmapDirName:
+ dirname = mainwindow.bitmapDirName
+ else:
+ dirname = mainwindow.dirname
+
+ fd = qt.QFileDialog(self, 'open dialog', True)
+ fd.setDir( dirname )
+ fd.setMode( qt.QFileDialog.ExistingFile )
+ fd.setFilters ( "Portable Network Graphics (*.png);;"
+ "Graphics Interchange Format (*.gif);;"
+ "Microsoft Bitmap (*.bmp);;"
+ "JPEG (*.jpeg *.jpg);;"
+ "MNG (*.mng);;"
+ "PBM (*.pbm);;"
+ "PGM (*.pgm);;"
+ "PPM (*.ppm);;"
+ "XBM (*.xbm);;"
+ "XPM (*.xpm)" )
+ fd.setCaption('Select Image')
+ # if the user chooses a file
+ if fd.exec_loop() == qt.QDialog.Accepted:
+ mainwindow.bitmapDirName = fd.dir()
+ self.edit.setText(unicode(fd.selectedFile()))
+ self.validateAndSet()
+ def done(self):
+ """Delete modification notification."""
+ self.setting.removeOnModified(self.onModified)
+
+ def validateAndSet(self):
+ """Check the text is a valid setting and update it."""
+
+ text = unicode(self.edit.text())
+ try:
+ val = self.setting.fromText(text)
+ self.setPaletteBackgroundColor(self.bgcolour)
+
+ # value has changed
+ if self.setting.get() != val:
+ self.setting.set(val)
+
+ except setting.InvalidType:
+ self.setPaletteBackgroundColor(qt.QColor('red'))
+
+ def onModified(self, setting, mod):
+ """called when the setting is changed remotely"""
+ self.edit.setText( self.setting.toText() )
+
Index: setting/setting.py
===================================================================
RCS file: /cvs/veusz/veusz/setting/setting.py,v
retrieving revision 1.20
diff -u -r1.20 setting.py
--- setting/setting.py 30 Jun 2005 20:40:09 -0000 1.20
+++ setting/setting.py 22 Jul 2005 22:32:12 -0000
@@ -33,6 +33,7 @@
import qt
import utils
+from utils import measurement
import controls
import widgets
from settingdb import settingdb
@@ -51,7 +52,7 @@
self.parent = None
self.name = name
self.descr = descr
- self.default = val
+ self.default = self.convertFrom(val)
self.onmodified = []
self.set(val)
@@ -159,7 +160,7 @@
"""Save the stored setting."""
self.val = self.convertTo( val )
for i in self.onmodified:
- i(True)
+ i(self, True)
def setSilent(self, val):
"""Set the setting, without propagating modified flags.
@@ -352,91 +353,51 @@
def makeControl(self, *args):
return controls.SettingChoice(self, True, ['Auto'], *args)
-
-# these are functions used by the distance setting below.
-# they don't work as class methods
-
-def _calcPixPerPt(painter):
- """Calculate the numbers of pixels per point for the painter.
-
- This is stored in the variable veusz_pixperpt."""
-
- dm = qt.QPaintDeviceMetrics(painter.device())
- painter.veusz_pixperpt = dm.logicalDpiY() / 72.
-
-def _distPhys(match, painter, mult):
- """Convert a physical unit measure in multiples of points."""
-
- if not hasattr(painter, 'veusz_pixperpt'):
- _calcPixPerPt(painter)
-
- return int( math.ceil(painter.veusz_pixperpt * mult *
- float(match.group(1)) * painter.veusz_scaling ) )
-
-def _distPerc(match, painter, maxsize):
- """Convert from a percentage of maxsize."""
-
- return int( math.ceil(maxsize * 0.01 * float(match.group(1))) )
-
-def _distFrac(match, painter, maxsize):
- """Convert from a fraction a/b of maxsize."""
-
- return int( math.ceil(maxsize * float(match.group(1)) /
- float(match.group(2))) )
-
-def _distRatio(match, painter, maxsize):
- """Convert from a simple 0.xx ratio of maxsize."""
-
- # if it's greater than 1 then assume it's a point measurement
- if float(match.group(1)) > 1.:
- return _distPhys(match, painter, 1)
-
- return int( math.ceil(maxsize * float(match.group(1))) )
-
-# mappings from regular expressions to function to convert distance
-# the recipient function takes regexp match,
-# painter and maximum size of frac
-_distregexp = [ ( re.compile('^([0-9\.]+) *%$'),
- _distPerc ),
- ( re.compile('^([0-9\.]+) */ *([0-9\.]+)$'),
- _distFrac ),
- ( re.compile('^([0-9\.]+) *pt$'),
- lambda match, painter, t:
- _distPhys(match, painter, 1.) ),
- ( re.compile('^([0-9\.]+) *cm$'),
- lambda match, painter, t:
- _distPhys(match, painter, 28.452756) ),
- ( re.compile('^([0-9\.]+) *mm$'),
- lambda match, painter, t:
- _distPhys(match, painter, 2.8452756) ),
- ( re.compile('^([0-9\.]+) *(inch|in|")$'),
- lambda match, painter, t:
- _distPhys(match, painter, 72.27) ),
- ( re.compile('^([0-9\.]+)$'),
- _distRatio )
- ]
-
class Distance(Setting):
"""A veusz distance measure, e.g. 1pt or 3%."""
-
def isDist(self, dist):
"""Is the text a valid distance measure?"""
-
- dist = dist.strip()
- for reg, fn in _distregexp:
- if reg.match(dist):
- return True
-
- return False
+
+ matchFound = False
+ for measure in measurement.measurementClasses.values():
+ if measure.matches(dist):
+ matchFound=True
+ break
+ return matchFound
def convertTo(self, val):
if self.isDist(val):
- return val
+ for measure in measurement.measurementClasses.values():
+ if measure.matches(val):
+ measureVal = measure()
+ measureVal.fromStr(val)
+ return measureVal
+ raise InvalidType
else:
raise InvalidType
+ def convertFrom(self, val):
+ return str(val)
+
+ def getUnit(self):
+ """Return the unit system in which the value is measured"""
+ return self.val.name
+
+ def setUnit(self, painter, name):
+ """Alter the unit system in which the value is measured"""
+ painterValue = self.val.toPainter(painter)
+ newMeasurement = measurement.measurementClasses[name]()
+ newMeasurement.fromPainter(painter, painterValue)
+ self.set(str(newMeasurement))
+
+ def toPainter(self, painter):
+ return self.val.toPainter(painter)
+
+ def fromPainter(self, painter):
+ return self.val.fromPainter(painter)
+
def toText(self):
- return self.val
+ return str(self.val)
def fromText(self, text):
if self.isDist(text):
@@ -447,46 +408,31 @@
def makeControl(self, *args):
return controls.SettingDistance(self, *args)
- def convert(self, painter):
- '''Convert a distance to plotter units.
+ def convert(self, painter, units=None, withSuffix=True):
+ '''Convert a distance to plotter units and return as a string.
- dist: eg 0.1 (fraction), 10% (percentage), 1/10 (fraction),
- 10pt, 1cm, 20mm, 1inch, 1in, 1" (size)
- maxsize: size fractions are relative to
- painter: painter to get metrics to convert physical sizes
+ painter - the painter with which the conversion is performed
+ units - the type of units to return
+ withSuffix - append the suffix to the units (if one exists) e.g. cm
'''
-
- # we set a scaling variable in the painter if it's not set
- if 'veusz_scaling' not in painter.__dict__:
- painter.veusz_scaling = 1.
-
- # work out maximum size
- try:
- maxsize = max( *painter.veusz_page_size )
- except AttributeError:
- w = painter.window()
- maxsize = max(w.width(), w.height())
-
- dist = self.val.strip()
-
- # compare string against each regexp
- for reg, fn in _distregexp:
- m = reg.match(dist)
-
- # if there's a match, then call the appropriate conversion fn
- if m:
- return fn(m, painter, maxsize)
-
- # none of the regexps match
- raise ValueError( "Cannot convert distance in form '%s'" %
- dist )
+ #TODO: Make conversions not produce loads of dp (maybe make set round to 1px?)
+ if not units:
+ return self.val.toPainter(painter)
+ else:
+ painterValue = self.val.toPainter(painter, False)
+ measure = measurement.measurementClasses[units]()
+ measure.fromPainter(painter, painterValue)
+ rv = str(measure)
+ if (not withSuffix) and measure.suffix:
+ rv = rv[:rv.index(measure.suffix)]
+ return rv
def convertPts(self, painter):
- """Get the distance in points."""
- if not hasattr(painter, 'veusz_pixperpt'):
- _calcPixPerPt(painter)
+ return float(self.convert(painter, "pt", False))
+
+ def getUnit(self):
+ return self.val.name
- return self.convert(painter) / painter.veusz_pixperpt
class Choice(Setting):
"""One out of a list of strings."""
@@ -691,3 +637,7 @@
return controls.DatasetChoose(self, self.document, self.dimensions,
*args)
+class Filename(Str):
+ def makeControl(self, *args):
+ """Allow user to choose between the datasets."""
+ return controls.FilenameSetting(self, *args)
Index: setting/settings.py
===================================================================
RCS file: /cvs/veusz/veusz/setting/settings.py,v
retrieving revision 1.9
diff -u -r1.9 settings.py
--- setting/settings.py 28 Jun 2005 20:43:58 -0000 1.9
+++ setting/settings.py 22 Jul 2005 22:32:12 -0000
@@ -76,7 +76,7 @@
if readonly:
setting.readonly = True
- def setModified(self, modified = True):
+ def setModified(self, setting=None, modified = True):
"""Set the modification flag."""
self.modified = modified
self.changeset += 1
Index: widgets/__init__.py
===================================================================
RCS file: /cvs/veusz/veusz/widgets/__init__.py,v
retrieving revision 1.7
diff -u -r1.7 __init__.py
--- widgets/__init__.py 26 Jun 2005 14:06:29 -0000 1.7
+++ widgets/__init__.py 22 Jul 2005 22:32:12 -0000
@@ -22,6 +22,7 @@
from widget import *
from axis import *
+from bitmap import *
from graph import *
from containers import *
from plotters import *
Index: windows/mainwindow.py
===================================================================
RCS file: /cvs/veusz/veusz/windows/mainwindow.py,v
retrieving revision 1.42
diff -u -r1.42 mainwindow.py
--- windows/mainwindow.py 12 Jul 2005 10:06:56 -0000 1.42
+++ windows/mainwindow.py 22 Jul 2005 22:32:13 -0000
@@ -30,6 +30,7 @@
import treeeditwindow
import document
import utils
+from utils import measurement
import setting
import dialogs.aboutdialog
@@ -62,6 +63,17 @@
self.plot = plotwindow.PlotWindow(self.document, self)
self.plotzoom = 0
+ #Create a painter object that is accessible everywhere.
+ #This should be used for unit conversions only, not for actual painting
+ #XXX - Do we even need a real painter here?
+ self.painter = qt.QPainter(self.plot)
+ self.painter.veusz_scaling = self.plot.zoomfactor
+ if not measurement.windowPxPerPt:
+ measurement.calcPixPerPt(self.painter)
+ measurement.windowPxPerPt = self.painter.veusz_pixperpt
+ self.painter.veusz_page_size = self.document.basewidget.getSize(self.painter)
+ self.painter.end()
+
# likewise with the tree-editing window
self.treeedit = treeeditwindow.TreeEditWindow(self.document, self)
self.moveDockWindow( self.treeedit, qt.Qt.DockLeft, True, 1 )
@@ -84,6 +96,9 @@
self.statusBar().addWidget(self.pagelabel)
self.dirname = ''
+ #Dir to use for loading bitmaps
+ self.bitmapDirName = ''
+ #Dir for file export
self.exportDir = ''
self.connect( self.plot, qt.PYSIGNAL("sigUpdatePage"),
Index: windows/plotwindow.py
===================================================================
RCS file: /cvs/veusz/veusz/windows/plotwindow.py,v
retrieving revision 1.25
diff -u -r1.25 plotwindow.py
--- windows/plotwindow.py 12 Jun 2005 17:12:45 -0000 1.25
+++ windows/plotwindow.py 22 Jul 2005 22:32:13 -0000
@@ -36,12 +36,14 @@
class PlotWindow( qt.QScrollView ):
"""Class to show the plot(s) in a scrollable window."""
- def __init__(self, document, *args):
+ def __init__(self, document, mainwindow, *args):
"""Initialise the window."""
- qt.QScrollView.__init__(self, *args)
+ qt.QScrollView.__init__(self, mainwindow, *args)
self.viewport().setBackgroundMode( qt.Qt.NoBackground )
+ self.mainwindow = mainwindow
+
# set up so if document is modified we are notified
self.document = document
self.docchangeset = -100
@@ -77,6 +79,8 @@
painter = qt.QPainter( self )
painter.veusz_scaling = self.zoomfactor
size = self.document.basewidget.getSize(painter)
+ if hasattr(self.mainwindow, 'painter'):
+ self.mainwindow.painter.veusz_page_size = size
painter.end()
# make new buffer and resize widget
measurement.py
Description: application/python
bitmap.py
Description: application/python
