Пример #1
0
class AtomGeneratorPropertyManager(PM_Dialog):
    """ Implements user interface to specify properties of an atom """

    # The title that appears in the property manager header.
    title = "Insert Atom"
    # The name of this property manager. This will be set to
    # the name of the PM_Dialog object via setObjectName().
    pmName = title
    # The relative path to PNG file that appears in the header.
    iconPath = "ui/actions/Command Toolbar/BuildAtoms/InsertAtom.png"

    # Jeff 20070530:
    # Private static variables (prefixed with '_s') are used to assure consistency
    # between related widgets and simplify code revision.
    # Example: The unit for coordinates is specified by _sCoordinateUnit.  All
    # widgets related to coordinates should refer to _sCoordinateUnit rather than
    # hardcoding the unit for each coordinate widget.  The advantage comes when
    # a later revision uses different units (or chosen possibly via a user
    # preference), the value of only _sCoordinateUnit (not blocks of code)
    # needs to be changed.  All related widgets follow the new choice for units.

    _sMinCoordinateValue   = -30.0
    _sMaxCoordinateValue   =  30.0
    _sStepCoordinateValue  =  0.1
    _sCoordinateDecimals   =  3
    _sCoordinateUnit       =  'Angstrom'
    _sCoordinateUnits      =  _sCoordinateUnit + 's'

    def __init__(self):
        """
        Construct the Atom Property Manager.
        """
        PM_Dialog.__init__( self, self.pmName, self.iconPath, self.title )
        self.addGroupBoxes()
        self.add_whats_this_text()

        msg = "Edit the Atom parameters and select <b>Preview</b> to \
        preview the structure. Click <b>Done</b> to insert the atom \
        into the model."

        # This causes the "Message" box to be displayed as well.
        self.MessageGroupBox.insertHtmlMessage( msg, setAsDefault = False )

    def getCartesianCoordinates(self):
        """
        Gets the cartesian coordinates for the position of the atom
        specified in the coordinate spin boxes of the Atom Generator
        property manager.
        """
        return ( self.xCoordinateField.value,
                 self.yCoordinateField.value,
                 self.zCoordinateField.value )

    def getMinCoordinateValue(self):
        """
        Get the minimum value allowed in the coordinate spin boxes
        of the Atom Generator property manager.
        """
        return self.sel_sMinCoordinateValue

    def getMaxCoordinateValue(self):
        """
        Get the maximum value allowed in the coordinate
        spin boxes of the Atom Generator property manager.
        """
        return self._sMaxCoordinateValue

    def getStepCoordinateValue(self):
        """
        Get the value by which a coordinate increases/decreases
        when the user clicks an arrow of a coordinate spin box
        in the Atom Generator property manager.
        """
        return self._sStepCoordinateValue

    def getCoordinateDecimals(self):
        """
        Get the number of decimal places given for a value in a
        coordinate spin box in the Atom Generator property manager.
        """
        return self._sStepCoordinateValue

    def getCoordinateUnit(self):
        """
        Get the unit (of measure) for the coordinates of the
        generated atom's position.
        """
        return self._sCoordinateUnit

    def setCartesianCoordinates( self, inX, inY, inZ ):
        """
        Set the cartesian coordinates for the position of the atom
        specified in the coordinate spin boxes of the Atom Generator
        property manager.
        """
        # We may want to restrict
        self.xCoordinateField.value  =  inX
        self.yCoordinateField.value  =  inY
        self.zCoordinateField.value  =  inZ

    def setMinCoordinateValue( self, inMin ):
        """
        Set the minimum value allowed in the coordinate spin boxes
        of the Atom Generator property manager.
        """
        self._sMinCoordinateValue  =  inMin

    def setMaxCoordinateValue( self, inMax ):
        """
        Set the maximum value allowed in the coordinate
        spin boxes of the Atom Generator property manager.
        """
        self._sMaxCoordinateValue  =  inMax

    def setStepCoordinateValue( self, inStep ):
        """
        Set the value by which a coordinate increases/decreases
        when the user clicks an arrow of a coordinate spin box
        in the Atom Generator property manager.
        """
        self._sStepCoordinateValue  =  inStep

    def setCoordinateDecimals( self, inDecimals ):
        """
        Set the number of decimal places given for a value in a
        coordinate spin box in the Atom Generator property manager.
        """
        self._sStepCoordinateValue  =  inDecimals

    def setCoordinateUnit( self, inUnit ):
        """
        Set the unit(s) (of measure) for the coordinates of the
        generated atom's position.
        """
        self._sCoordinateUnit   =  inUnit
        self._sCoordinateUnits  =  inUnit + 's'

    def addGroupBoxes(self):
        """
        Add the 1 groupbox for the Atom Property Manager.
        """

        self.pmGroupBox1 = \
            PM_GroupBox( self,
                         title =  "Atom Position" )

        self.loadGroupBox1(self.pmGroupBox1)

        self.pmElementChooser =  PM_ElementChooser(self)

        AddTestGroupBoxes = True # For testing. Mark 2007-05-24

        if not AddTestGroupBoxes: # Add test widgets to their own groupbox.
            return


        """
        self.testGroupBox1 = \
            PM_GroupBox( self,
                         title = "Test Widgets1" )

        self.loadTestWidgets1(self.testGroupBox1)

        self.pmLineEditGroupBox = \
            PM_GroupBox( self,
                         title = "PM_LineEdit Widgets" )

        self.loadLineEditGroupBox(self.pmLineEditGroupBox)
        """

        """
        self.radioButtonGroupBox = \
            PM_GroupBox( self,
                         title =  "PM_RadioButtons" )

        self.loadRadioButtonGroupBox(self.radioButtonGroupBox)


        self.pmToolButtonGroupBox = \
            PM_GroupBox( self,
                         title = "MMKit Widget" )

        self.loadToolButtonGroupBox(self.pmToolButtonGroupBox)
        """

    def loadGroupBox1(self, inPmGroupBox):
        """
        Load widgets into groupbox 1.
        """

        # User input to specify x-coordinate
        # of the generated atom's position.
        self.xCoordinateField  =  \
            PM_DoubleSpinBox( inPmGroupBox,
                              label         =  \
                              "ui/actions/Properties Manager/X_Coordinate.png",
                              value         =  0.0,
                              setAsDefault  =  True,
                              minimum       =  self._sMinCoordinateValue,
                              maximum       =  self._sMaxCoordinateValue,
                              singleStep    =  self._sStepCoordinateValue,
                              decimals      =  self._sCoordinateDecimals,
                              suffix        =  ' ' + self._sCoordinateUnits )

        # User input to specify y-coordinate
        # of the generated atom's position.
        self.yCoordinateField  =  \
            PM_DoubleSpinBox( inPmGroupBox,
                              label         =  \
                              "ui/actions/Properties Manager/Y_Coordinate.png",
                              value         =  0.0,
                              setAsDefault  =  True,
                              minimum       =  self._sMinCoordinateValue,
                              maximum       =  self._sMaxCoordinateValue,
                              singleStep    =  self._sStepCoordinateValue,
                              decimals      =  self._sCoordinateDecimals,
                              suffix        =  ' ' + self._sCoordinateUnits )

        # User input to specify z-coordinate
        # of the generated atom's position.
        self.zCoordinateField = \
            PM_DoubleSpinBox( inPmGroupBox,
                              label         =  \
                              "ui/actions/Properties Manager/Z_Coordinate.png",
                              value         =  0.0,
                              setAsDefault  =  True,
                              minimum       =  self._sMinCoordinateValue,
                              maximum       =  self._sMaxCoordinateValue,
                              singleStep    =  self._sStepCoordinateValue,
                              decimals      =  self._sCoordinateDecimals,
                              suffix        =  ' ' + self._sCoordinateUnits )


    def add_whats_this_text(self):
        """
        What's This... text for some of the widgets in the
        Atom Property Manager.
        :Jeff 2007-05-30:
        """

        self.xCoordinateField.setWhatsThis("<b>x</b><p>: The x-coordinate (up "\
                                           "to </p>" \
                                           + str( self._sMaxCoordinateValue ) \
                                           + self._sCoordinateUnits \
                                           + ") of the Atom in " \
                                           + self._sCoordinateUnits + '.')

        self.yCoordinateField.setWhatsThis("<b>y</b><p>: The y-coordinate (up" \
                                           "to </p>"\
                                           + str( self._sMaxCoordinateValue ) \
                                           + self._sCoordinateUnits \
                                           + ") of the Atom in " \
                                           + self._sCoordinateUnits + '.')

        self.zCoordinateField.setWhatsThis("<b>z</b><p>: The z-coordinate (up" \
                                           "to </p>" \
                                           + str( self._sMaxCoordinateValue )
                                           + self._sCoordinateUnits \
                                           + ") of the Atom in "
                                           + self._sCoordinateUnits + '.')




    def loadTestWidgets1(self, inPmGroupBox):
        """
        Adds widgets to <inPmGroupBox>.
        Used for testing purposes. Mark 2007-05-24
        """

        # I intend to create a special PropMgr to display all widget types
        # for testing purposes. For now, I just add them to the end of the
        # Graphene Sheet property manager. Mark 2007-05-22

        self.spinBox = \
            PM_SpinBox( inPmGroupBox,
                        label        = "Spinbox:",
                        value        = 5,
                        setAsDefault = True,
                        minimum      = 2,
                        maximum      = 10,
                        suffix       = ' things',
                        spanWidth    = True )

        self.doubleSpinBox = \
            PM_DoubleSpinBox( inPmGroupBox,
                              #label="Spanning DoubleSpinBox :",
                              label        = "", # No label
                              value        = 5.0,
                              setAsDefault = True,
                              minimum      = 1.0,
                              maximum      = 10.0,
                              singleStep   = 1.0,
                              decimals     = 1,
                              suffix       = ' Suffix',
                              spanWidth    = True )

        # Add a prefix example.
        self.doubleSpinBox.setPrefix("Prefix ")

        choices = [ "First", "Second", "Third (Default)", "Forth" ]

        self.comboBox1= \
            PM_ComboBox( inPmGroupBox,
                         label        = 'Choices: ',
                         choices      = choices,
                         index        = 2,
                         setAsDefault = True,
                         spanWidth    = False )

        self.comboBox2= \
            PM_ComboBox( inPmGroupBox,
                         label        = ' :Choices',
                         labelColumn  = 1,
                         choices      = choices,
                         index        = 2,
                         setAsDefault = True,
                         spanWidth    = False )

        self.comboBox3= \
            PM_ComboBox( inPmGroupBox,
                         label        = ' Choices (SpanWidth = True):',
                         labelColumn  = 1,
                         choices      = choices,
                         index        = 2,
                         setAsDefault = True,
                         spanWidth    = True )

        self.textEdit = \
            PM_TextEdit( inPmGroupBox,
                         label     = "TextEdit:",
                         spanWidth = False )


        self.spanTextEdit = \
            PM_TextEdit( inPmGroupBox,
                         label     = "",
                         spanWidth = True )


        self.groupBox = \
            PM_GroupBox( inPmGroupBox,
                         title          = "Group Box Title" )

        self.comboBox2= \
            PM_ComboBox( self.groupBox,
                         label        = "Choices:",
                         choices      = choices,
                         index        = 2,
                         setAsDefault = True,
                         spanWidth    = False )

        self.groupBox2 = \
            PM_GroupBox( inPmGroupBox,
                         title          = "Group Box Title" )

        self.comboBox3= \
            PM_ComboBox( self.groupBox2,
                         label        = "Choices:",
                         choices      = choices,
                         index        = 2,
                         setAsDefault = True,
                         spanWidth    = True )

        self.pushButton1 = \
            PM_PushButton( inPmGroupBox,
                           label = "",
                           text  = "PushButton1" )

        self.pushButton2 = \
            PM_PushButton( inPmGroupBox,
                           label     = "",
                           text      = "PushButton2",
                           spanWidth = True )

    def loadLineEditGroupBox(self, inPmGroupBox):
        """
        Load PM_LineEdit test widgets in group box.
        """

        self.lineEdit1 = \
            PM_LineEdit( inPmGroupBox,
                         label        = "Name:",
                         text         = "RotaryMotor-1",
                         setAsDefault = True,
                         spanWidth    = False)

        self.lineEdit2 = \
            PM_LineEdit( inPmGroupBox,
                         label        = ":Name",
                         labelColumn  = 1,
                         text         = "RotaryMotor-1",
                         setAsDefault = True,
                         spanWidth    = False)

        self.lineEdit3 = \
            PM_LineEdit( inPmGroupBox,
                         label        = "LineEdit (spanWidth = True):",
                         text         = "RotaryMotor-1",
                         setAsDefault = False,
                         spanWidth    = True)

    def loadCheckBoxGroupBox(self, inPmGroupBox):
        """
        Load PM_CheckBox test widgets in group box.
        """
        self.checkBoxGroupBox = \
            PM_GroupBox( inPmGroupBox,
                         title          = "<b> PM_CheckBox examples</b>" )

        self.checkBox1 = \
            PM_CheckBox( self.checkBoxGroupBox,
                         text         = "Widget on left:",
                         widgetColumn = 1,
                         state        = Qt.Checked,
                         setAsDefault = True,
                        )

        self.checkBox2 = \
            PM_CheckBox( self.checkBoxGroupBox,
                         text         = "Widget on right",
                         widgetColumn  = 1,
                         state        = Qt.Checked,
                         setAsDefault = True,
                         )


    def loadRadioButtonGroupBox(self, inPmGroupBox):
        """
        Test for PM_RadioButtonGroupBox.
        """
        #from PyQt4.Qt import QButtonGroup
        #self.radioButtonGroup = QButtonGroup()
        #self.radioButtonGroup.setExclusive(True)

        self.radioButton1 = \
            PM_RadioButton( inPmGroupBox,
                            label     = "Display PM_CheckBox group box",
                            spanWidth =  False)

        self.radioButton2 = \
            PM_RadioButton( inPmGroupBox,
                            label     = "Display PM_ComboBox group box",
                            spanWidth =  False)

        self.radioButton3 = \
            PM_RadioButton( inPmGroupBox,
                            label     = "Display PM_DoubleSpinBox group box",
                            spanWidth =  False)

        self.radioButton4 = \
            PM_RadioButton( inPmGroupBox,
                            label     = "Display PM_PushButton group box",
                            spanWidth =  False)
class test_connectWithState_PM( ExampleCommand1_PM):

    # does not use GBC; at least Done & Cancel should work
    
    title = "test connectWithState"
    
    def _addGroupBoxes(self):
        """Add the groupboxes for this Property Manager."""
        self.pmGroupBox1 = PM_GroupBox( self, title =  "settings")
        self._loadGroupBox1(self.pmGroupBox1)
        self.pmGroupBox2 = PM_GroupBox( self, title =  "commands")
        self._loadGroupBox2(self.pmGroupBox2)
        return

    _sMaxCylinderHeight = 20 ### TODO: ask the stateref for this
    
    def _loadGroupBox1(self, pmGroupBox):
        """Load widgets into groupbox 1 (passed as pmGroupBox)."""

        # cylinder height (a double, stored as a preferences value)

        cylinderHeight_stateref = Preferences_StateRef_double(
            CYLINDER_HEIGHT_PREFS_KEY,
            CYLINDER_HEIGHT_DEFAULT_VALUE )
            ### TODO: ask model object for this ref; this code should not need to know what kind it is (from prefs or model)
        
        self.cylinderHeightSpinbox  =  \
            PM_DoubleSpinBox( pmGroupBox,
                              label         =  "cylinder height:",
##                              value         =  CYLINDER_HEIGHT_DEFAULT_VALUE,
##                              # guess: default value or initial value (guess they can't be distinguished -- bug -- yes, doc confirms)
##                              setAsDefault  =  True,
                              ### TODO: get all the following from the stateref, whenever the connection to state is made
                              minimum       =  3,
                              maximum       =  self._sMaxCylinderHeight,
                              singleStep    =  0.25,
                              decimals      =  self._sCoordinateDecimals,
                              suffix        =  ' ' + self._sCoordinateUnits )
        # REVIEW: is it ok that the above will set some wrong defaultValue,
        # to be immediately corrected by the following connection with state?
        self.cylinderHeightSpinbox.connectWithState(
            cylinderHeight_stateref,
            debug_metainfo = True
         )

        # ==
        
        # cylinder width (a double, stored in the command object,
        #  defined there using the State macro -- note, this is not yet a good
        #  enough example for state stored in a Node)

        cylinderWidth_stateref = ObjAttr_StateRef( self.commandrun, 'cylinderWidth')

        ## TEMPORARY: just make sure it's defined in there
        junk = cylinderWidth_stateref.defaultValue
        
        self.cylinderWidthSpinbox  =  \
            PM_DoubleSpinBox( pmGroupBox,
                              label         =  "cylinder width:",
##                              value         =  defaultValue,
##                              setAsDefault  =  True,
##                                  ### REVISE: the default value should come from the cylinderWidth_stateref
                                  # (and so, probably, should min, max, step, units...)
                              minimum       =  0.1,
                              maximum       =  15.0,
                              singleStep    =  0.1,
                              decimals      =  self._sCoordinateDecimals,
                              suffix        =  ' ' + self._sCoordinateUnits )
        
        self.cylinderWidthSpinbox.connectWithState(
                                cylinderWidth_stateref,
                                debug_metainfo = True )

        # ==
        
        # cylinder round caps (boolean)
        
        cylinderRoundCaps_stateref = Preferences_StateRef( CYLINDER_ROUND_CAPS_PREFS_KEY,
                                                           CYLINDER_ROUND_CAPS_DEFAULT_VALUE ) ### TODO: get from model
        ## TEMPORARY: just make sure it's defined in there
        junk = cylinderRoundCaps_stateref.defaultValue
        
        self.cylinderRoundCapsCheckbox = PM_CheckBox(pmGroupBox, text = 'round caps on cylinder')
##        self.cylinderRoundCapsCheckbox.setDefaultValue(CYLINDER_ROUND_CAPS_DEFAULT_VALUE)
##            # note: setDefaultValue is an extension to the PM_CheckBox API, not yet finalized
        self.cylinderRoundCapsCheckbox.connectWithState(
                                cylinderRoundCaps_stateref,
                                debug_metainfo = True )

        # ==
        
        # cylinder vertical or horizontal (boolean)
        cylinderVertical_stateref = ObjAttr_StateRef( self.commandrun, 'cylinderVertical' )
        
        self.cylinderVerticalCheckbox = PM_CheckBox(pmGroupBox, text = 'cylinder is vertical')
##        self.cylinderVerticalCheckbox.setDefaultValue(CYLINDER_VERTICAL_DEFAULT_VALUE)
##            ### REVISE: the default value should come from the stateref
        self.cylinderVerticalCheckbox.connectWithState(
                                cylinderVertical_stateref,
                                debug_metainfo = True )
        
        return # from _loadGroupBox1

    def _loadGroupBox2(self, pmGroupBox): ### RENAME button attrs
        self.startButton = \
            PM_PushButton( pmGroupBox,
                           label     = "",
                           text      = "Bigger",
                           spanWidth = False ) ###BUG: button spans PM width, in spite of this setting
        self.startButton.setAction( self.button_Bigger, cmdname = "Bigger")
        
        self.stopButton = \
            PM_PushButton( pmGroupBox,
                           label     = "",
                           text      = "Smaller",
                           spanWidth = False )
        self.stopButton.setAction( self.button_Smaller, cmdname = "Smaller")

        return
        
    def button_Bigger(self):
        self.commandrun.cmd_Bigger()

    def button_Smaller(self):
        self.commandrun.cmd_Smaller()
        
    def _addWhatsThisText(self):
        """What's This text for some of the widgets in the Property Manager."""
        self.cylinderHeightSpinbox.setWhatsThis("cylinder height (stored in prefs)")
        self.cylinderWidthSpinbox.setWhatsThis("cylinder width (stored as State in the command object)")
        return
    
    pass # end of class
Пример #3
0
class PM_Dialog_with_example_widgets(PM_Dialog):
    """
    [private] PM_Dialog with some PM widgets common to several examples here
    """
    # NOTE: contains some code copied (and perhaps modified) from AtomGeneratorDialog.py

    # these class constants should be defined by each specific PM subclass
    # (we don't define them here, since we want errors to occur if you don't override them)
    #   title = "title"
    #   pmName = "pm" + title
    #   iconPath = "path-to-some-icon.png"

    #k all needed?
    _sMinCoordinateValue = -30.0
    _sMaxCoordinateValue = 30.0
    _sStepCoordinateValue = 0.1
    _sCoordinateDecimals = 4
    _sCoordinateUnit = 'Angstrom'
    _sCoordinateUnits = _sCoordinateUnit + 's'
    _sElementSymbolList = ["H", "O", "C", "S"]

    def __init__(self):
        PM_Dialog.__init__(self, self.pmName, self.iconPath, self.title)

        msg = "Example command created at %s" % time.asctime()

        # This causes the "Message" box to be displayed as well.
        self.MessageGroupBox.insertHtmlMessage(msg, setAsDefault=False)
        return

    def _addGroupBoxes(self):
        """
        Add group boxes to this Property Manager.
        """
        self.pmGroupBox1 = PM_GroupBox(self, title="Atom Parameters")
        self._loadGroupBox1(self.pmGroupBox1)
        return

    def _loadGroupBox1(self, inPmGroupBox):
        """
        Load widgets into group box 1.
        """

        # User input to specify what type of element/atom to generate
        elementComboBoxItems = self._sElementSymbolList
        self.elementComboBox  =  \
            PM_ComboBox( inPmGroupBox,
                         label         =  "Elements :",
                         choices       =  elementComboBoxItems,
                         index         =  0,
                         setAsDefault  =  True,
                         spanWidth     =  False )

        # User input to specify x-coordinate
        # of the generated atom's position.
        self.xCoordinateField  =  \
            PM_DoubleSpinBox( inPmGroupBox,
                              label         =  "x :",
                              value         =  0.0,
                              setAsDefault  =  True,
                              minimum       =  self._sMinCoordinateValue,
                              maximum       =  self._sMaxCoordinateValue,
                              singleStep    =  self._sStepCoordinateValue,
                              decimals      =  self._sCoordinateDecimals,
                              suffix        =  ' ' + self._sCoordinateUnits )
        return

    def _addWhatsThisText(self):
        """
        What's This text for some of the widgets in the Property Manager.
        """

        self.xCoordinateField.setWhatsThis(
            "<b>x</b><p>: The x-coordinate (up to </p>" +
            str(self._sMaxCoordinateValue) + self._sCoordinateUnits +
            ") of the Atom in " + self._sCoordinateUnits + '.')

    pass  # end of class PM_Dialog_with_example_widgets
Пример #4
0
class PM_Dialog_with_example_widgets( PM_Dialog):
    """
    [private] PM_Dialog with some PM widgets common to several examples here
    """
    # NOTE: contains some code copied (and perhaps modified) from AtomGeneratorDialog.py

    # these class constants should be defined by each specific PM subclass
    # (we don't define them here, since we want errors to occur if you don't override them)
    #   title = "title"
    #   pmName = "pm" + title
    #   iconPath = "path-to-some-icon.png"

    #k all needed?
    _sMinCoordinateValue   = -30.0
    _sMaxCoordinateValue   =  30.0
    _sStepCoordinateValue  =  0.1
    _sCoordinateDecimals   =  4
    _sCoordinateUnit       =  'Angstrom'
    _sCoordinateUnits      =  _sCoordinateUnit + 's'
    _sElementSymbolList    =  ["H","O","C","S"]

    def __init__(self):
        PM_Dialog.__init__( self, self.pmName, self.iconPath, self.title )
               
        msg = "Example command created at %s" % time.asctime()
        
        # This causes the "Message" box to be displayed as well.
        self.MessageGroupBox.insertHtmlMessage( msg, setAsDefault = False )
        return

    def _addGroupBoxes(self):
        """
        Add group boxes to this Property Manager.
        """
        self.pmGroupBox1 = PM_GroupBox( self, title =  "Atom Parameters" )
        self._loadGroupBox1(self.pmGroupBox1)
        return
    
    def _loadGroupBox1(self, inPmGroupBox):
        """
        Load widgets into group box 1.
        """

        # User input to specify what type of element/atom to generate
        elementComboBoxItems  =  self._sElementSymbolList
        self.elementComboBox  =  \
            PM_ComboBox( inPmGroupBox,
                         label         =  "Elements :",
                         choices       =  elementComboBoxItems,
                         index         =  0,
                         setAsDefault  =  True,
                         spanWidth     =  False )
        
        # User input to specify x-coordinate 
        # of the generated atom's position.
        self.xCoordinateField  =  \
            PM_DoubleSpinBox( inPmGroupBox,
                              label         =  "x :",
                              value         =  0.0,
                              setAsDefault  =  True,
                              minimum       =  self._sMinCoordinateValue,
                              maximum       =  self._sMaxCoordinateValue,
                              singleStep    =  self._sStepCoordinateValue,
                              decimals      =  self._sCoordinateDecimals,
                              suffix        =  ' ' + self._sCoordinateUnits )
        return
        
    def _addWhatsThisText(self):
        """
        What's This text for some of the widgets in the Property Manager.
        """
        
        self.xCoordinateField.setWhatsThis("<b>x</b><p>: The x-coordinate (up to </p>"
                                           + str( self._sMaxCoordinateValue )
                                           + self._sCoordinateUnits
                                           + ") of the Atom in "
                                           + self._sCoordinateUnits + '.')
    pass # end of class PM_Dialog_with_example_widgets
class test_connectWithState_PM( ExampleCommand1_PM):

    # does not use GBC; at least Done & Cancel should work
    
    title = "test connectWithState"
    
    def _addGroupBoxes(self):
        """
        Add the groupboxes for this Property Manager.
        """
        self.pmGroupBox1 = PM_GroupBox( self, title =  "settings")
        self._loadGroupBox1(self.pmGroupBox1)
        self.pmGroupBox2 = PM_GroupBox( self, title =  "commands")
        self._loadGroupBox2(self.pmGroupBox2)
        return

    _sMaxCylinderHeight = 20 ### TODO: ask the stateref for this
    
    def _loadGroupBox1(self, pmGroupBox):
        """
        Load widgets into groupbox 1 (passed as pmGroupBox).
        """
        # cylinder height (a double, stored as a preferences value)

        cylinderHeight_stateref = Preferences_StateRef_double(
            CYLINDER_HEIGHT_PREFS_KEY,
            CYLINDER_HEIGHT_DEFAULT_VALUE )
            ### TODO: ask model object for this ref; this code should not need to know what kind it is (from prefs or model)
        
        self.cylinderHeightSpinbox  =  \
            PM_DoubleSpinBox( pmGroupBox,
                              label         =  "cylinder height:",
##                              value         =  CYLINDER_HEIGHT_DEFAULT_VALUE,
##                              # guess: default value or initial value (guess they can't be distinguished -- bug -- yes, doc confirms)
##                              setAsDefault  =  True,
                              ### TODO: get all the following from the stateref, whenever the connection to state is made
                              minimum       =  3,
                              maximum       =  self._sMaxCylinderHeight,
                              singleStep    =  0.25,
                              decimals      =  self._sCoordinateDecimals,
                              suffix        =  ' ' + self._sCoordinateUnits )
        # REVIEW: is it ok that the above will set some wrong defaultValue,
        # to be immediately corrected by the following connection with state?
        self.cylinderHeightSpinbox.connectWithState(
            cylinderHeight_stateref,
            debug_metainfo = True
         )

        # ==
        
        # cylinder width (a double, stored in the command object,
        #  defined there using the State macro -- note, this is not yet a good
        #  enough example for state stored in a Node)

        cylinderWidth_stateref = ObjAttr_StateRef( self.command, 'cylinderWidth')

        ## TEMPORARY: just make sure it's defined in there
        junk = cylinderWidth_stateref.defaultValue
        
        self.cylinderWidthSpinbox  =  \
            PM_DoubleSpinBox( pmGroupBox,
                              label         =  "cylinder width:",
##                              value         =  defaultValue,
##                              setAsDefault  =  True,
##                                  ### REVISE: the default value should come from the cylinderWidth_stateref
                                  # (and so, probably, should min, max, step, units...)
                              minimum       =  0.1,
                              maximum       =  15.0,
                              singleStep    =  0.1,
                              decimals      =  self._sCoordinateDecimals,
                              suffix        =  ' ' + self._sCoordinateUnits )
        
        self.cylinderWidthSpinbox.connectWithState(
                                cylinderWidth_stateref,
                                debug_metainfo = True )

        # ==
        
        # cylinder round caps (boolean)
        
        cylinderRoundCaps_stateref = Preferences_StateRef( CYLINDER_ROUND_CAPS_PREFS_KEY,
                                                           CYLINDER_ROUND_CAPS_DEFAULT_VALUE ) ### TODO: get from model
        ## TEMPORARY: just make sure it's defined in there
        junk = cylinderRoundCaps_stateref.defaultValue
        
        self.cylinderRoundCapsCheckbox = PM_CheckBox(pmGroupBox, text = 'round caps on cylinder')
##        self.cylinderRoundCapsCheckbox.setDefaultValue(CYLINDER_ROUND_CAPS_DEFAULT_VALUE)
##            # note: setDefaultValue is an extension to the PM_CheckBox API, not yet finalized
        self.cylinderRoundCapsCheckbox.connectWithState(
                                cylinderRoundCaps_stateref,
                                debug_metainfo = True )

        # ==
        
        # cylinder vertical or horizontal (boolean)
        cylinderVertical_stateref = ObjAttr_StateRef( self.command, 'cylinderVertical' )
        
        self.cylinderVerticalCheckbox = PM_CheckBox(pmGroupBox, text = 'cylinder is vertical')
##        self.cylinderVerticalCheckbox.setDefaultValue(CYLINDER_VERTICAL_DEFAULT_VALUE)
##            ### REVISE: the default value should come from the stateref
        self.cylinderVerticalCheckbox.connectWithState(
                                cylinderVertical_stateref,
                                debug_metainfo = True )
        
        return # from _loadGroupBox1

    def _loadGroupBox2(self, pmGroupBox): ### RENAME button attrs
        self.startButton = \
            PM_PushButton( pmGroupBox,
                           label     = "",
                           text      = "Bigger",
                           spanWidth = False ) ###BUG: button spans PM width, in spite of this setting
        self.startButton.setAction( self.button_Bigger, cmdname = "Bigger")
        
        self.stopButton = \
            PM_PushButton( pmGroupBox,
                           label     = "",
                           text      = "Smaller",
                           spanWidth = False )
        self.stopButton.setAction( self.button_Smaller, cmdname = "Smaller")

        return
        
    def button_Bigger(self):
        self.command.cmd_Bigger()

    def button_Smaller(self):
        self.command.cmd_Smaller()
        
    def _addWhatsThisText(self):
        """
        What's This text for some of the widgets in the Property Manager.
        """
        self.cylinderHeightSpinbox.setWhatsThis("cylinder height (stored in prefs)")
        self.cylinderWidthSpinbox.setWhatsThis("cylinder width (stored as State in the command object)")
        return
    
    pass # end of class