=================================================
wx: wxPython Widgets for Epics
=================================================

.. module:: wx
   :synopsis: wxPython Widgets for Epics

The :mod:`wx` module of :mod:`epics` (that is, **epics.wx**) provides a set
of wxPython classes for epics PVs. Most of these are derived from wxPython
widgets, with special support added for epics PVs, especially regarding
when to automatically update the widget based on a changing value for a PV.

.. _pyepics applications:    https://github.com/pyepics/epicsapps

Some examples of code that uses pyepics and wxPython are included in the
*scripts* folder of the pyepics source distribution kit.  In addition,
there are a some full-fledged applications using Epics and wxPython at
`pyepics applications`_.

..  _wx-functions-label:

PV-aware Widgets
=========================

Several basic wxPython widgets have been extended so as to connect the
widget with a corresponding `PV`.  For example, setting the text value of a
:mod:`PVTextCtrl` will forward that value to the epics `PV`, and if the
`PV` is changed by externally, the value displayed in the widget will be
automatically updated.


PVMixin
~~~~~~~~~~~~

.. class:: PVMixin([pv=None[, pvname=None]])

   This is a mixin class for wx Controls with epics PVs:  This connects to
   PV, and manages connection and callback events for the PV.  It provides
   the following basic methods used by most of the PV<->widget classes
   below.

.. method::   SetPV(pv=None)

   set the PV corresponding to the widget.

.. method::   Update(value=None)

   set the widgets value from the PV's value.   If value=``None``, the current
   value for the PV is used.

.. method::   GetValue(as_string=True)

   return the PVs value.

.. method::   OnEpicsConnect()

   PV connection event handler.

.. method::   OnPVChange(value)

   PV monitor (subscription) event handler.  Must be overwritten for each
   widget type.

.. method::  GetEnumStrings()

   return enumeration strings for the PV


PVCtrlMixin
~~~~~~~~~~~~~~~

.. class:: PVCtrlMixin(parent, pv=None, font=None, fg=None, bg=None, **kw)

   This is a mixin class for wx Controls with epics PVs:  This subclasses
   PVCtrlMixin and adds colour translations
   PV, and manages callback events for the PV.

  :param parent: wx parent widget
  :param pv:     epics.PV
  :param font: wx.Font for display
  :param fg:   foreground colour
  :param bg:   background colour


   A class that inherits from this class **must** provide a method called
   `_SetValue`, which will set the contents of the corresponding widget
   when the PV's value changes.

   In general, the widgets will automatically update when the PV
   changes. Where appropriate, setting the value with the widget will set
   the PV value.


PVText
~~~~~~~~~


.. class:: PVText(parent, pv=None, font=None, fg=None, bg=None, minor_alarm="DARKRED", major_alarm="RED", invalid_alarm="ORANGERED", auto_units=False, units="", **kw)

  derived from wx.StaticText and PVCtrlMixin, this is a StaticText widget
  whose value is set to the string representation of the value for the
  corresponding PV.

  By default, the text colour will be overridden when the PV enters an
  alarm state. These colours can be modified (or disabled by being set
  to ``None``) as part of the constructor.

  "units" specifies a unit suffix (like ' A' or ' mm') to put after the text
  value whenever it is displayed.

  Alternatively, "auto_units" means the control will automatically display
  the "EGU" units value from the PV, whenever it updates. If this value is
  set, "units" is ignored. A space is inserted between the value and the
  unit.


PVTextCtrl
~~~~~~~~~~~

.. class:: PVTextCtrl(parent, pv=None, font=None, fg=None, bg=None, dirty_timeout=2500, **kw)

    derived from wx.TextCtrl and PVCtrlMixin, this is a TextCtrl widget
    whose value is set to the string representation of the value for the
    corresponding PV.

	 Setting the value (hitting Return or Enter) or changing focus away
	 from the widget will set the PV value immediately. Otherwise, the
	 widget will wait for 'dirty_timeout' milliseconds after the last
	 keypress and then set the PV value to whatever is written in the field.


PVFloatCtrl
~~~~~~~~~~~

.. class:: PVFloatCtrl(parent, pv=None, font=None, fg=None, bg=None, **kw)

    A special variation of a wx.TextCtrl that allows only floating point
    numbers, as associated with a double, float, or integer PV.  Trying to
    type in a non-numerical value will be ignored.  Furthermore, if a PV's
    limits can be determined, they will be used to limit the allowed range
    of input values.  For a value that is within limits, the value will be
    `put` to the PV on return.  Out-of-limit values will be highlighted in
    a different color.


PVBitmap
~~~~~~~~~~~

.. class:: PVBitmap(parent, pv=None, bitmaps={}, defaultBitmap=None)

    A Static Bitmap where the image is based on PV value.

   If the bitmaps dictionary is set, it should be set as PV.Value(Bitmap)
   where particular bitmaps will be shown if the PV takes those certain values.

   If you need to do any more complex or dynamic drawing, you may want to look at the OGL PV controls.


PVCheckBox
~~~~~~~~~~~

.. class:: PVCheckBox(self, parent, pv=None, on_value=1, off_value=0, **kw)

    Checkbox based on a binary PV value, both reads/writes the PV on
    changes.  on_value and off_value are the specific values that are
    mapped to the checkbox.

    There are multiple options for translating PV values to checkbox
    settings (from least to most complex):

    * Use a PV with values 0 and 1
    * Use a PV with values that convert via Python's own bool(x)
    * Set on_value and off_value in the constructor
    * Use SetTranslations() to set a dictionary for converting various
      PV values to booleans.


PVFloatSpin
~~~~~~~~~~~

.. class:: PVFloatSpin(parent, pv=None, deadTime=500, min_val=None, max_val=None, increment=1.0, digits=-1, **kw)

    A FloatSpin is a floating point spin control with buttons to increase
    and decrease the value by a particular increment. Arrow keys and page
    up/down can also be used (the latter changes the value by 10x the
    increment.)

    PVFloatSpin is a special derivation that assigns a PV to the FloatSpin
    control. deadTime is the delay (in milliseconds) between when the user
    finishes typing a value and when the PV is set to it (to prevent
    half-typed numeric values being set.)


PVButton
~~~~~~~~~~~

.. class:: PVButton(parent, pv=None, pushValue=1, disablePV=None,
                    disableValue=1, **kw)

    A wx.Button linked to a PV. When the button is pressed, 'pushValue' is
    written to the PV (useful for momentary PVs with HIGH= set.)  Setting
    disablePV and disableValue will automatically cause the button to
    disable when that PV has a certain value.

PVBitmapButton
~~~~~~~~~~~~~~~~

.. class:: PVBitmapButton(parent, pv=None, bitmap = 'image.png', pushValue=1, disablePV=None,
                    disableValue=1, **kw)

    A wx.BitmapButton linked to a PV. When the button is pressed, 'pushValue' is written to the PV (useful for momentary PVs with HIGH= set.)  Setting
    disablePV and disableValue will automatically cause the button to
    disable when that PV has a certain value. A bitmap from file is loaded and displayed instead of a label. 

PVRadioButton
~~~~~~~~~~~~~

.. class:: PVRadioButton(parent, pv=None, pvValue=None, **kw)

    A PVRadioButton is a radio button associated with a particular PV and
    one particular value.

    Suggested for use in a group where all radio buttons are
    PVRadioButtons, and they all have a discrete value set.


PVComboBox
~~~~~~~~~~~

.. class:: PVComboBox(parent, pv=None, **kw)

    A ComboBox linked to a PV. Both reads/writes the combo value on
    changes.


PVEnumComboBox
~~~~~~~~~~~~~~~~

.. class:: PVEnumComboBox(parent, pv=None, **kw)

    A ComboBox linked to an "enum" type PV (such as bi, bo, mbbi, mbbo.) The ComboBox
	 is automatically populated with a non-editable list of the PV enum values, allowing
	 the user to select them from the dropdown.

	 Both reads/writes the combo value on changes.


PVEnumButtons
~~~~~~~~~~~~~~~~~~

.. class:: PVEnumButtons(parent, pv=None, font=None, fg=None, bg=None, **kw)

   This will create a wx.Panel of buttons (a button bar), 1 for each
   enumeration state of an enum PV.  The set of buttons will correspond to
   the current state of the PV


PVEnumChoice
~~~~~~~~~~~~~~~~~~

.. class:: PVEnumChoice(parent, pv=None, font=None, fg=None, bg=None, **kw)

   This will create a dropdown list (a wx.Choice) with a list of
   enumeration states for an enum PV.


PVAlarm
~~~~~~~~~~

.. class:: PVAlarm(parent, pv=None, font=None, fg=None, bg=None, trip_point=None, **kw)

    This will create a pop-up message (wx.MessageDialog) that is shown when
    the corresponding PV trips the alarm level.

PVCollapsiblePane
~~~~~~~~~~~~~~~~~

.. class:: PVCollapsiblePane(parent,  pv=None, minor_alarm="DARKRED", major_alarm="RED", invalid_alarm="ORANGERED", **kw)

    This is equivalent to wx.CollapsiblePane, except the label shown
    on the pane's "expansion button" comes from a PV.

    The additional keyword arguments can be any of the other constructor
    arguments supported by wx.CollapsiblePane.

    By default, the foreground colour of the pane button will be overridden
    when the PV enters an alarm state. On GTK, this means the colour of the
    triangular drop-down button but not the label text. These colours can
    be modified (or disabled by being set to ``None``) as part of the
    constructor.

    Supports the .SetTranslation() method, whose argument is a dictionary
    mapping PV values to display labels. If the PV value is not found in
    the dictionary, it will displayed verbatim as the label.


Decorators and other Utility Functions
==========================================


.. function:: DelayedEpicsCallback

decorator to wrap an Epics callback in a wx.CallAfter,
so that the wx and epics ca threads do not clash
This also checks for dead wxPython objects (say, from a
closed window), and remove callbacks to them.

..  function::  EpicsFunction

decorator to wrap function in a wx.CallAfter() so that
Epics calls can be made in a separate thread, and asynchronously.

This decorator should be used for all code that mix calls to wx and epics

..  function::  finalize_epics

This function will finalize epics, and close all Channel Access
communication, by calling :meth:`epics.ca.finalize_libca`.  This may be
useful when closing an application, as in a method bound to `wx.EVT_CLOSE`
event from a top-level application window.  Be careful to **not** call this
function when closing a Window if your application is not closing, and if
you are still doing any Channel Access work in the other windows.



wxMotorPanel Widget
========================

A dedicated wx Widget for Epics Motors is included in the :mod:`wx` module
that provides an easy-to-use Motor panel that is similar to the normal MEDM
window, but with a few niceties from the more sophisticated wx
toolkit. This widget can be used simply as::

    import wx
    from epics.wx import MotorPanel
    ....
    mymotor = MotorPanel(parent, 'XXX:m1')

A sample panel looks like this

.. image:: wx_motor.png

Which shows from right to left: the motor description, an information
message (blank most of the time), the readback value, the drive value,
arrows to tweak the motor, and a drop-down combobox for tweak values, a
"Stop" button and a "More" button.  The panel has the following features:

   *  All controls are "live" and will respond to changes from other source.
   *  The values for the tweak values in the ComboBox are automatically
      generated from the precision and travel range of the motor.
   *  The entry box for the drive value will *only* accept numeric input,
      and will only set the drive value when hitting Enter or Return.
   *  The drive value  will change to Red text on a Yellow background when
      the value in the box violates the motors (user) limits.  If Enter or
      Return when the the displayed value violates the limit, the motor
      will not be moved, but the displayed value will be changed to the
      closest limit value.
   *  Pressing the "Stop" button will stop the motor (with the `.SPMG`
      field), and set the Info field to "Stopped".  The button label will
      change to "Go", and the motor will not move until this button is pressed.

Finally, the "More" button will bring up a more complete form of Motor
parameters that looks like:

.. image:: wx_motordetail.png

Many such MotorPanels can be put in a vertical stack, as generated from the
'wx_motor.py' script in the scripts folder of the source distribution as::

   ~>python wx_motor.py XXX:m1 XXX:m2 XXX:m3 XXX:m4

will look like this:

.. image:: wx_motor_many.png


OGL Classes
===========

OGL is a graphics drawing library shipped with wxPython. Is it built around
the concept of "shapes" which are added to "canvases" and can be moved,
scrolled, zoomed, animated, etc.

There is a PVShapeMixin class which allows PV callback functionality to be
added to any OGL Shape class, and there are also PVRectangle and PVCircle
subclasses already created.

A recommended way to use these OGL classes is to make a static bitmap
background for your display, place it in an OGL Canvas and then add an
overlay of shapes which appear/disappear/resize/change colour based on
the PV values.

PVShapeMixin
~~~~~~~~~~~~~~~~

.. class:: PVShapeMixin(self, pv=None, pvname=None)

  Similar to PVMixin, this mixin should be added to any
  ogl.Shape subclass that needs PV callback support.

  The main method is PVChanged(self, raw_value), which should be
  overridden in the subclass to provide specific processing based on
  the changed value.

  There are also some built-in pieces of functionality. These are
  enough to do simple show/hide or change colour shape functionality,
  without needing to write specific code.

  SetBrushTranslations(translations) allows setting a dict of PV Value ->
  wx.Brush mappings, which can be used to automatically repaint the shape
  foreground (fill) when the PV changes.

  SetPenTranslations(translations) similar to brush translations, but
  the values are wx.Pen instances that are used to repaint the shape
  outline when the PV changes.

  SetShownTranslations(translations) sets a dictionary of PV Value ->bool
  values which are used to show/hide the shape depending on the PV value,
  as it changes.


PVRectangle
~~~~~~~~~~~

.. class:: PVRectangle(self, w, h, pv=None, pvname=None)

   A PVCtrlMixin for the Rectangle shape class.


PVCircle
~~~~~~~~

.. class::  PVCircle(self, diameter, pv=None, pvname=None)

   A PVCtrlMixin for the Circle shape class.
