Source code for camelot.view.controls.editors.floateditor

#  ============================================================================
#
#  Copyright (C) 2007-2013 Conceptive Engineering bvba. All rights reserved.
#  www.conceptive.be / info@conceptive.be
#
#  This file is part of the Camelot Library.
#
#  This file may be used under the terms of the GNU General Public
#  License version 2.0 as published by the Free Software Foundation
#  and appearing in the file license.txt included in the packaging of
#  this file.  Please review this information to ensure GNU
#  General Public Licensing requirements will be met.
#
#  If you are unsure which license is appropriate for your use, please
#  visit www.python-camelot.com or contact info@conceptive.be
#
#  This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
#  WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#
#  For use of this library in commercial applications, please contact
#  info@conceptive.be
#
#  ============================================================================

from PyQt4 import QtGui
from PyQt4 import QtCore
from PyQt4.QtCore import Qt

from customeditor import CustomEditor, set_background_color_palette, draw_tooltip_visualization
from camelot.view.art import Icon
from camelot.core import constants

[docs]class CustomDoubleSpinBox(QtGui.QDoubleSpinBox): """Spinbox that doesn't accept mouse scrolling as input""" def __init__(self, option = None, parent = None): super(CustomDoubleSpinBox, self).__init__(parent) self._option = option self._locale = QtCore.QLocale() def wheelEvent(self, wheel_event): wheel_event.ignore() def keyPressEvent(self, key_event): # Disable the default behaviour when pressing the up or down arrow # which would respectively increment and decrement the value # inside the spinbox. This custom behaviour is only applicable # when being displayed inside a table view, hence the version check. # By ignoring key_event, the table view itself is scrolled instead. if self._option and self._option.version != 5 and key_event.key() in (Qt.Key_Up, Qt.Key_Down): key_event.ignore() else: decimal_point = QtCore.QLocale.system().decimalPoint() # Make sure that the Period key on the numpad is *always* # represented by the systems locale decimal separator to # facilitate user input. if key_event.key() == Qt.Key_Period and decimal_point.unicode() != Qt.Key_Period: # Dynamically build a 'new' event that holds this locales decimal separator new_key_event = QtGui.QKeyEvent( key_event.type(), decimal_point.unicode(), key_event.modifiers(), QtCore.QString(decimal_point) ) key_event.accept() # Block 'old' event QtGui.QApplication.sendEvent(self, new_key_event) # Propagate all other events to the super class else: super(CustomDoubleSpinBox, self).keyPressEvent(key_event) def textFromValue(self, value): text = unicode( self._locale.toString( float(value), 'f', self.decimals() ) ) return text def paintEvent(self, event): super(CustomDoubleSpinBox, self).paintEvent(event) if self.toolTip(): draw_tooltip_visualization(self)
[docs]class FloatEditor(CustomEditor): """Widget for editing a float field, with a calculator button. The calculator button can be turned of with the **calculator** field attribute. """ calculator_icon = Icon('tango/16x16/apps/accessories-calculator.png') def __init__(self, parent, minimum = constants.camelot_minfloat, maximum = constants.camelot_maxfloat, calculator = True, decimal = False, option = None, field_name = 'float', **kwargs): CustomEditor.__init__(self, parent) self.setObjectName( field_name ) self.setSizePolicy( QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed ) self._decimal = decimal self._calculator = calculator action = QtGui.QAction(self) action.setShortcut( QtGui.QKeySequence( Qt.Key_F4 ) ) self.setFocusPolicy(Qt.StrongFocus) self.spinBox = CustomDoubleSpinBox(option, parent) self.spinBox.setRange(minimum, maximum) self.spinBox.setDecimals(2) self.spinBox.setAlignment(Qt.AlignRight|Qt.AlignVCenter) self.spinBox.addAction(action) self.calculatorButton = QtGui.QToolButton() self.calculatorButton.setIcon( self.calculator_icon.getQIcon() ) self.calculatorButton.setAutoRaise(True) self.calculatorButton.setFixedHeight(self.get_height()) self.calculatorButton.setToolTip('Calculator F4') self.calculatorButton.setFocusPolicy(Qt.ClickFocus) self.calculatorButton.clicked.connect( lambda:self.popupCalculator(self.spinBox.value()) ) action.triggered.connect( lambda:self.popupCalculator(self.spinBox.value()) ) self.spinBox.editingFinished.connect( self.spinbox_editing_finished ) self.releaseKeyboard() layout = QtGui.QHBoxLayout() layout.setContentsMargins( 0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(self.spinBox) layout.addWidget(self.calculatorButton) self.setFocusProxy(self.spinBox) self.setLayout(layout) def set_field_attributes(self, editable = True, background_color = None, tooltip = None, prefix = '', suffix = '', precision = 2, single_step = 1.0, **kwargs): self.set_enabled(editable) self.set_background_color(background_color) self.spinBox.setToolTip(unicode(tooltip or '')) self.spinBox.setPrefix(u'%s '%(unicode(prefix or '').lstrip())) self.spinBox.setSuffix(u' %s'%(unicode(suffix or '').rstrip())) self.spinBox.setSingleStep(single_step) if self.spinBox.decimals() != precision: self.spinBox.setDecimals( precision ) def set_value(self, value): value = CustomEditor.set_value(self, value) if value: self.spinBox.setValue( float(value) ) elif value == None: self.spinBox.lineEdit().setText('') else: self.spinBox.setValue(0.0) def get_value(self): value_loading = CustomEditor.get_value(self) if value_loading is not None: return value_loading if self.spinBox.text()=='': return None self.spinBox.interpretText() value = self.spinBox.value() if self._decimal: import decimal value = decimal.Decimal('%.*f' % (self.spinBox.decimals(), value)) return value def set_enabled(self, editable=True): self.spinBox.setReadOnly(not editable) self.spinBox.setEnabled(editable) self.calculatorButton.setShown(editable and self._calculator) if editable: self.spinBox.setButtonSymbols(QtGui.QAbstractSpinBox.UpDownArrows) else: self.spinBox.setButtonSymbols(QtGui.QAbstractSpinBox.NoButtons) def popupCalculator(self, value): from camelot.view.controls.calculator import Calculator calculator = Calculator(self) calculator.setValue(value) calculator.calculation_finished_signal.connect( self.calculation_finished ) calculator.exec_() @QtCore.pyqtSlot(QtCore.QString) def calculation_finished(self, value): self.spinBox.setValue(float(unicode(value))) self.editingFinished.emit() @QtCore.pyqtSlot() def spinbox_editing_finished(self): self.editingFinished.emit() def set_background_color(self, background_color): # # WARNING : Changing this code requires extensive testing of all editors # in all states on all platforms (Mac, Linux, Win XP, Win Vista, Win 7) # # There seems to be a bug in Windows QStyle that requires the spinbox as # well as its line edit to require the bgcolor to be set, was however # unable to reproduce this properly in a test case # set_background_color_palette( self.spinBox.lineEdit(), background_color ) set_background_color_palette( self.spinBox, background_color )