Attached is the patch I mentioned to add a dropdown combo box containing
the distance measures. The patch seems to work - doing things like
entering "25cm" will correctly parse out the units and update the
combobox and lineedit. The major piece of wierdness is that selecting
"fraction" in the dropdown with a number > 1 will actually choose "pts"
(this is what the code in utilfuncs.py actually does, but it doesn't
seem like great UI).
_However_
The patch is kinda ugly, for example there's some quite involved logic
to determine what happens if you enter a value without units. I'm not
quite sure what the best way to make it prettier is. Suggestions?
Index: setting/controls.py
===================================================================
RCS file: /cvs/veusz/veusz/setting/controls.py,v
retrieving revision 1.6
diff -u -r1.6 controls.py
--- setting/controls.py 25 Mar 2005 18:11:38 -0000 1.6
+++ setting/controls.py 19 Apr 2005 20:24:48 -0000
@@ -24,6 +24,7 @@
import qt
import setting
+import utils
class SettingEdit(qt.QLineEdit):
"""Main control for editing settings which are text."""
@@ -70,7 +71,88 @@
def onModified(self, mod):
"""called when the setting is changed remotely"""
self.setText( self.setting.toText() )
+
+class DistanceSettingEdit(qt.QHBox):
+ def __init__(self, setting, parent):
+ qt.QWidget.__init__(self,parent)
+
+ self.setting=setting
+ self.bgcolour = self.paletteBackgroundColor()
+
+ self.box = qt.QHBox(self)
+
+ self.valueBox = qt.QLineEdit(self,"valueBox")
+
+ self.unitsCombo = qt.QComboBox(0,self,"unitsCombo")
+
+ self.unitsCombo.setEditable(False)
+ self.unitsCombo.clear()
+
+ units = utils.getDistUnitNames()
+ del units[units.index("ratio")]
+
+ for item in units:
+ self.unitsCombo.insertItem(item)
+
+ self.connect(self.unitsCombo, qt.SIGNAL('activated(const QString&)'),
+ self.validateAndSet)
+
+ self.setting.setOnModified(self.onModified)
+
+ self.connect(self.valueBox, qt.SIGNAL('lostFocus()'),
+ self.validateAndSet)
+ self.connect(self.valueBox, qt.SIGNAL('returnPressed()'),
+ self.validateAndSet)
+ self.updateFromString(setting.toText(), True)
+
+ def updateFromString(self, string, noUnitsIsRatio=False):
+ """Take a string and set the values of the controls appropriately"""
+ value,unit = utils.splitDist(string)
+ self.valueBox.setText(value)
+ #If the value returned is ratio, there are three possibilites
+ # - we are being called from the lineEdit being modified without
+ # a specific unit- in this case we want to keep the current unit
+ # - a dimenionless unit < 1 is specified in the lineEdit- this
+ # indicates a decimal fraction of the maximum allowed size
+ # - a dimenionless unit > 1 is specified in the lineEdit- this converts
+ # the unit to points
+ if unit=="ratio":
+ if noUnitsIsRatio:
+ if float(value) > 1:
+ unit = "pt"
+ else:
+ unit = "fraction"
+ self.unitsCombo.setCurrentText(unit)
+ else:
+ self.unitsCombo.setCurrentText(unit)
+
+ def done(self):
+ """Delete modification notification."""
+ self.setting.removeOnModified(self.onModified)
+
+ def validateAndSet(self):
+ """Check the text is a valid setting and update it."""
+ self.updateFromString(str(self.valueBox.text()))
+
+ if not(self.unitsCombo.currentText() == "fraction"):
+ text = str(self.valueBox.text()) + str(self.unitsCombo.currentText())
+ else:
+ text = str(self.valueBox.text())
+ try:
+ val = self.setting.fromText(text)
+ self.valueBox.setPaletteBackgroundColor(self.bgcolour)
+
+ # value has changed
+ if self.setting.get() != val:
+ self.setting.set(val)
+
+ except setting.InvalidType:
+ self.valueBox.setPaletteBackgroundColor(qt.QColor('red'))
+
+ def onModified(self, mod):
+ self.updateFromString(self.setting.toText(), True)
+
class BoolSettingEdit(qt.QCheckBox):
"""A check box for changing a bool setting."""
Index: setting/setting.py
===================================================================
RCS file: /cvs/veusz/veusz/setting/setting.py,v
retrieving revision 1.10
diff -u -r1.10 setting.py
--- setting/setting.py 9 Apr 2005 22:20:02 -0000 1.10
+++ setting/setting.py 19 Apr 2005 20:24:48 -0000
@@ -364,7 +364,7 @@
raise InvalidType
def makeControl(self, *args):
- return controls.SettingEdit(self, *args)
+ return controls.DistanceSettingEdit(self, *args)
class Choice(Setting):
"""One out of a list of strings."""
Index: utils/utilfuncs.py
===================================================================
RCS file: /cvs/veusz/veusz/utils/utilfuncs.py,v
retrieving revision 1.14
diff -u -r1.14 utilfuncs.py
--- utils/utilfuncs.py 2 Apr 2005 16:55:32 -0000 1.14
+++ utils/utilfuncs.py 19 Apr 2005 20:24:50 -0000
@@ -313,31 +313,51 @@
# the recipient function takes regexp match, painter and maximum size of frac
_distRegexp=[ (re.compile('^([0-9\.]+) *%$'),
- _distPerc),
+ _distPerc, "%"),
(re.compile('^([0-9\.]+) */ *([0-9\.]+)$'),
- _distFrac),
+ _distFrac, "fraction"),
(re.compile('^([0-9\.]+) *pt$'),
- lambda match, painter, t: _distPhys(match, painter, 1.)),
+ lambda match, painter, t: _distPhys(match, painter, 1.), "pt"),
(re.compile('^([0-9\.]+) *cm$'),
- lambda match, painter, t: _distPhys(match, painter, 28.452756)),
+ lambda match, painter, t: _distPhys(match, painter, 28.452756), "cm"),
(re.compile('^([0-9\.]+) *mm$'),
- lambda match, painter, t: _distPhys(match, painter, 2.8452756)),
+ lambda match, painter, t: _distPhys(match, painter, 2.8452756), "mm"),
(re.compile('^([0-9\.]+) *(inch|in|")$'),
- lambda match, painter, t: _distPhys(match, painter, 72.27)),
+ lambda match, painter, t: _distPhys(match, painter, 72.27), "in"),
(re.compile('^([0-9\.]+)$'),
- _distRatio)
+ _distRatio, "ratio")
]
def isDist(dist):
"""Is the text a valid distance measure?"""
dist = dist.strip()
- for reg, fn in _distRegexp:
+ for reg, fn, name in _distRegexp:
if reg.match(dist) != None:
return True
return False
+def getDistUnitNames():
+ return [name for reg, fn, name in _distRegexp]
+
+def splitDist(dist):
+ """Split a string containing a value+units into a magnitude,unit tuple
+ Note: a return value of "Ratio" indicates no specific unit
+ """
+ dist=dist.strip()
+ for reg, fn, unit in _distRegexp:
+ match= reg.match(dist)
+ if match != None:
+ if unit == "fraction":
+ value = dist
+ else:
+ value = match.group(1)
+ return value,unit
+ #XXX - do we want to raise an error here?
+ return False
+
+
def cnvtDist(dist, painter):
'''Convert a distance to plotter units.
@@ -361,7 +381,7 @@
dist = dist.strip()
# compare string against each regexp
- for reg, fn in _distRegexp:
+ for reg, fn, name in _distRegexp:
m = reg.match(dist)
# if there's a match, then call the appropriate conversion fn