/ docs / src / gui / pyvcp.txt
pyvcp.txt
   1  [[cha:pyvcp]]
   2  
   3  = Python Virtual Control Panel
   4  
   5  == Introduction
   6  
   7  .Python Virtual Control Panel
   8  
   9  The PyVCP (Python Virtual Control Panel) is designed to give the
  10  integrator the ability to customize the AXIS interface with buttons and
  11  indicators to do special tasks.
  12  
  13  Hardware machine control panels can use up a lot of I/O pins and can
  14  be expensive. That is where Virtual Control Panels have the advantage
  15  as well as it cost nothing to build a PyVCP.
  16  
  17  Virtual Control Panels can be used for testing or monitoring things to
  18  temporarily replace real I/O devices while debugging ladder logic, or
  19  to simulate a physical panel before you build it and wire it to an I/O
  20  board.
  21  
  22  The following graphic displays many of the PyVCP widgets.
  23  
  24  image::images/pyvcp_group.png[]
  25  
  26  == Panel Construction
  27  
  28  The layout of a PyVCP panel is specified with an XML file that
  29  contains widget tags between <pyvcp> and </pyvcp>. For example:
  30  
  31  [source,xml]
  32  -------------------------------------------------
  33  <pyvcp>
  34      <label text="This is a LED indicator"/>
  35      <led/>
  36  </pyvcp>
  37  -------------------------------------------------
  38  
  39  image::images/pyvcp_mypanel.png[]
  40  
  41  If you place this text in a file called tiny.xml, and run
  42  
  43  ----------------------------------------------
  44  halcmd loadusr pyvcp -c mypanel tiny.xml
  45  ----------------------------------------------
  46  
  47  PyVCP will create the panel for you, which includes two widgets, a
  48  Label with the text 'This is a LED indicator', and a LED, used for
  49  displaying the state of a HAL BIT signal. It will also create a HAL
  50  component named 'mypanel' (all widgets in this panel are connected to
  51  pins that start with 'mypanel.'). Since no <halpin> tag was present
  52  inside the <led> tag, PyVCP will automatically name the HAL pin for the
  53  LED widget mypanel.led.0
  54  
  55  For a list of widgets and their tags and options, see the widget
  56  reference below.
  57  
  58  Once you have created your panel, connecting HAL signals to and from
  59  the PyVCP pins is done with the halcmd:
  60  
  61  -----------------------------------------------------------------------
  62  net <signal-name> <pin-name> <opt-direction> <opt-pin-name>signal-name
  63  -----------------------------------------------------------------------
  64  
  65  If you are new to HAL, the HAL basics chapter in the Integrator
  66  Manual is a good place to start.
  67  
  68  == Security
  69  
  70  Parts of PyVCP files are evaluated as Python code, and can take any
  71  action available to Python programs. Only use PyVCP .xml files from a
  72  source that you trust.
  73  
  74  [[sec:pyvcp-with-axis]]
  75  
  76  == AXIS
  77  
  78  Since AXIS uses the same GUI toolkit (Tkinter) as PyVCP, it is
  79  possible to include a PyVCP panel on the right side of the normal AXIS
  80  user interface. A typical example is explained below.
  81  
  82  Place your PyVCP XML file describing the panel in the same directory
  83  where your .ini file is. Say we we want to display the current spindle
  84  speed using a Bar widget. Place the following in a file called
  85  spindle.xml:
  86  
  87  [source,xml]
  88  -------------------------------------------------
  89  <pyvcp>
  90      <label>
  91          <text>"Spindle speed:"</text>
  92      </label>
  93      <bar>
  94          <halpin>"spindle-speed"</halpin>
  95          <max_>5000</max_>
  96      </bar>
  97  </pyvcp>
  98  -------------------------------------------------
  99  
 100  Here we've made a panel with a Label and a Bar widget, specified that
 101  the HAL pin connected to the Bar should be named 'spindle-speed', and
 102  set the maximum value of the bar to 5000 (see widget reference below
 103  for all options). To make AXIS aware of this file, and call it at start
 104  up, we need to specify the following in the [DISPLAY] section of the
 105  .ini file:
 106  
 107  -----------------------------
 108  PYVCP = spindle.xml
 109  -----------------------------
 110  
 111  To make our widget actually display the spindle-speed it needs to be
 112  hooked up to the appropriate HAL signal. A .hal file that will be run
 113  once AXIS and PyVCP have started can be specified in the [HAL] section
 114  of the .ini file:
 115  
 116  ---------------------------------------
 117  POSTGUI_HALFILE = spindle_to_pyvcp.hal
 118  ---------------------------------------
 119  
 120  This change will run the HAL commands specified in
 121  'spindle_to_pyvcp.hal'. In our example the contents could look like
 122  this:
 123  
 124  -------------------------------------------------
 125  net spindle-rpm-filtered => pyvcp.spindle-speed
 126  -------------------------------------------------
 127  
 128  assuming that a signal called 'spindle-rpm-filtered' already exists.
 129  Note that when running together with AXIS, all PyVCP widget HAL pins
 130  have names that start with 'pyvcp.'.
 131  
 132  image::images/pyvcp_axis_lathe.png[]
 133  
 134  This is what the newly created PyVCP panel should look like in AXIS.
 135  The 'sim/lathe' configuration is already configured this way.
 136  
 137  == Stand Alone
 138  
 139  This section describes how PyVCP panels can be displayed on their own
 140  with or without LinuxCNC's machine controller.
 141  
 142  To load a stand alone PyVCP panel with LinuxCNC use these commands:
 143  
 144  -----------------------------------------------------------------------
 145  loadusr -Wn mypanel pyvcp -g WxH+X+Y -c mypanel <path/>panel_file.xml
 146  -----------------------------------------------------------------------
 147  
 148  You would use this if you wanted a floating panel or a panel with a
 149  GUI other than AXIS.
 150  
 151  * '-Wn panelname' - 
 152       makes HAL wait for the component 'panelname' to finish loading
 153      ('become ready' in HAL speak) before processing more HAL commands. This
 154      is important because PyVCP panels export HAL pins, and other HAL
 155      components will need them present to connect to them. Note the capital
 156      W and lowercase n. If you use the -Wn option you must use the -c option
 157      to name the panel.
 158  
 159  * 'pyvcp < -g> < -c> panel.xml' - 
 160       builds the panel with the optional geometry and/or panelname from the
 161      xml panel file. The panel.xml can be any name that ends in .xml. The
 162      .xml file is the file that describes how to build the panel. You must
 163      add the path name if the panel is not in the directory that the HAL
 164      script is in. 
 165  
 166  * '-g <WxH><+X+Y>' - 
 167       specifies the geometry to be used when constructing the panel. The
 168      syntax is 'Width x Height + X Anchor + Y Anchor'. You can set the size
 169      or position or both. The anchor point is the upper left corner of the
 170      panel. An example is -g 250x500+800+0 This sets the panel at 250 pixels
 171      wide, 500 pixels tall, and anchors it at X800 Y0.
 172  
 173  * '-c panelname' - 
 174       tells PyVCP what to call the component and also the title of the
 175      window. The panelname can be any name without spaces. 
 176  
 177  To load a 'stand alone' PyVCP panel without LinuxCNC use this command:
 178  
 179  -----------------------------------------------------------------------
 180  loadusr -Wn mypanel pyvcp -g 250x500+800+0 -c mypanel mypanel.xml
 181  -----------------------------------------------------------------------
 182  
 183  The minimum command to load a pyvcp panel is:
 184  
 185  -----------------------------
 186  loadusr pyvcp mypanel.xml
 187  -----------------------------
 188  
 189  You would use this if you want a panel without LinuxCNC's machine
 190  controller such as for testing or a standalone DRO.
 191  
 192  The loadusr command is used when you also load a component that will
 193  stop HAL from closing until it's done. If you loaded a panel and then
 194  loaded Classic Ladder using 'loadusr -w classicladder',
 195  CL would hold HAL open (and the panel)  until you closed CL.
 196  The '-Wn' above means wait for the component '-Wn "name"' to become ready.
 197  ('name' can be any name. Note the capital W and lowercase n.)
 198  The -c tells PyVCP to build a panel with the
 199  name 'panelname' using the info in 'panel_file_name.xml'.
 200  The name 'panel_file_name.xml' can be any name but must end in .xml - it is the
 201  file that describes how to build the panel. You must add the path name
 202  if the panel is not in the directory that the HAL script is in.
 203  
 204  An optional command to use if you want the panel to stop HAL from
 205  continuing commands / shutting down. After loading any other components
 206  you want the last HAL command to be:
 207  
 208  -----------------------------
 209  waituser panelname
 210  -----------------------------
 211  
 212  This tells HAL to wait for component 'panelname' to close before
 213  continuing HAL commands. This is usually set as the last command so that
 214  HAL shuts down when the panel is closed.
 215  
 216  == Widgets
 217  
 218  HAL signals come in two variants, bits and numbers. Bits are off/on
 219  signals. Numbers can be 'float', 's32' or 'u32'. For more information on HAL
 220  data types see the <<sec:hal-data,HAL Data>> section. The PyVCP widget
 221  can either display the value of the signal with an indicator widget, or
 222  modify the signal value with a control widget. Thus there are four
 223  classes of PyVCP widgets that you can connect to a HAL signal. A fifth
 224  class of helper widgets allow you to organize and label your panel.
 225  
 226   . Widgets for indicating 'bit' signals: led, rectled
 227   . Widgets for controlling 'bit' signals: button, checkbutton, radiobutton
 228   . Widgets for indicating 'number' signals: number, s32, u32, bar, meter
 229   . Widgets for controlling 'number' signals: spinbox, scale, jogwheel
 230   . Helper widgets: hbox, vbox, table, label, labelframe
 231  
 232  === Syntax
 233  
 234  Each widget is described briefly, followed by the markup used, and a
 235  screen shot. All tags inside the main widget tag are optional.
 236  
 237  === General Notes
 238  
 239  At the present time, both a tag-based and an attribute-based syntax
 240  are supported. For instance, the following XML fragments are treated
 241  identically:
 242  
 243  [source,xml]
 244  ---------------------------------------
 245  <led halpin="my-led"/>
 246  ---------------------------------------
 247  
 248  and
 249  
 250  [source,xml]
 251  ---------------------------------------
 252  <led><halpin>"my-led"</halpin></led>
 253  ---------------------------------------
 254  
 255  When the attribute-based syntax is used, the following rules are used
 256  to turn the attributes value into a Python value:
 257  
 258   . If the first character of the attribute is one of the following, it is
 259     evaluated as a Python expression: '{(["''
 260   . If the string is accepted by int(), the value is treated as an integer
 261   . If the string is accepted by float(), the value is treated as
 262     floating-point
 263   . Otherwise, the string is accepted as a string.
 264  
 265  When the tag-based syntax is used, the text within the tag is always
 266  evaluated as a Python expression.
 267  
 268  The examples below show a mix of formats.
 269  
 270  .Comments
 271  
 272  To add a comment use the xml syntax for a comment.
 273  
 274  [source,xml]
 275  -----------------------------
 276  <!-- My Comment -->
 277  -----------------------------
 278  
 279  .Editing the XML file
 280  
 281  Edit the XML file with a text editor. In most cases you can right
 282  click on the file and select 'open with text editor' or similar.
 283  
 284  [[pyvcp-colors]]
 285  .Colors
 286  
 287  Colors can be specified using the X11 rgb colors by name 'gray75' or
 288  hex '#0000ff'. A complete list is located here
 289  http://sedition.com/perl/rgb.html[http://sedition.com/perl/rgb.html].
 290  
 291  Common Colors (colors with numbers indicate shades of that color)
 292  
 293   - white
 294   - black
 295   - blue and blue1 - 4
 296   - cyan and cyan1 - 4
 297   - green and green1 - 4
 298   - yellow and yellow1 - 4
 299   - red and red1 - 4
 300   - purple and purple1 - 4
 301   - gray and gray0 - 100
 302  
 303  .HAL Pins
 304  
 305  HAL pins provide a means to 'connect' the widget to something. Once
 306  you create a HAL pin for your widget you can 'connect' it to another
 307  HAL pin with a 'net' command in a .hal file. For more information on
 308  the 'net' command see the <<sec:hal-commands,HAL Commands>> section.
 309  
 310  === Label
 311  
 312  A label is a way to add text to your panel.
 313  
 314  * '<label></label>' - creates a label
 315  
 316  * '<text>"text"</text>' - the text to put in your label, a blank label can be
 317    used as a spacer to align other objects.
 318  
 319  * '<font>("Helvetica",20)</font>' - specificy the font and size of the text
 320  
 321  * '<relief>FLAT</relief>' - specificy the border around the label ('FLAT',
 322    'RAISED', 'SUNKEN') default is 'FLAT'
 323  
 324  * '<bd>n</bd>' - where 'n' is the border width when 'RAISED' or 'SUNKEN' borders
 325    are used.
 326  
 327  * '<padx>n</padx>' - where 'n' is the amount of extra horizontal extra space.
 328  
 329  * '<pady>n</pady>' - where 'n' is the amount of extra vertical extra space.
 330  
 331  The label has an optional disable pin that is created when you add
 332  '<disable_pin>True</disable_pin>'.
 333  
 334  [source,xml]
 335  -------------------------------------------------
 336  <label>
 337      <text>"This is a Label:"</text>
 338      <font>("Helvetica",20)</font>
 339  </label>
 340  -------------------------------------------------
 341  
 342  The above code produced this example. 
 343  
 344  image::images/pyvcp_label.png[]
 345  
 346  === Multi_Label
 347  
 348  An extention of the text label.
 349  
 350  Selectable text label, can display up to 6 label legends when associated bit pin
 351  is activated.
 352  
 353  Attach each legend pin to a signal and get a descriptive label when the signal
 354  is TRUE.
 355  
 356  If more than one legend pin is TRUE, the highest numbered 'TRUE' legend will be
 357  displayed.
 358  
 359  If a disable pin is created with '<disable_pin>True</disable_pin>' and that pin
 360  is set to true the lable changes to a grayed out state.
 361  
 362  [source,xml]
 363  ----
 364  <multilabel>
 365      <legends>["Label1", "Label2", "Label3", "Label4", "Label5", "Label6"]</legends>
 366      <font>("Helvetica",20)</font>
 367      <disable_pin>True</disable_pin>
 368  </multilabel>
 369  ----
 370  
 371  The above example would create the following pins.
 372  
 373  ----
 374  pyvcp.multilabel.0.disable
 375  pyvcp.multilabel.0.legend0
 376  pyvcp.multilabel.0.legend1
 377  pyvcp.multilabel.0.legend2
 378  pyvcp.multilabel.0.legend3
 379  pyvcp.multilabel.0.legend4
 380  pyvcp.multilabel.0.legend5
 381  ----
 382  
 383  If you have more than one multilabel the pins created would increment the number
 384  like this 'pyvcp.multilabel.1.legend1'.
 385  
 386  === LEDs
 387  
 388  A LED is used to indicate the status of a 'bit' halpin. The LED color
 389  will be on_color when the halpin is true, and off_color otherwise.
 390  
 391  * '<led></led>' - makes a round LED
 392  
 393  * '<rectled></rectled>' - makes a rectangle LED
 394  
 395  * '<halpin>name</halpin>' - 'name' of the pin, default is 'led.n', where
 396    n is an integer that is incremented for each LED.
 397  
 398  * '<size>n</size>' - 'n' is the size of the led in pixels, default is 20
 399  
 400  * '<on_color>color</on_color>' - sets the color of the LED when the pin is true.
 401    default is 'green'. See <<pyvcp-colors,colors>> for more info.
 402  
 403  * '<off_color>color</off_color>' - sets the color of the LED when the pin is
 404    false. default is 'red'
 405  
 406  * '<height>n</height>' - sets the height of the LED in pixels
 407  
 408  * '<width>n</width>' - sets the width of the LED in pixels
 409  
 410  * '<disable_pin>false</disable_pin>' - when true adds a disable pin to the led.
 411  
 412  * '<disabled_color>color</disabled_color>' - sets the color of the LED when the
 413    pin is disabled.
 414  
 415  .Round LED
 416  
 417  [source,xml]
 418  ---------------------------------------
 419  <led>
 420      <halpin>"my-led"</halpin>
 421      <size>50</size>
 422      <on_color>"green"</on_color>
 423      <off_color>"red"</off_color>
 424  </led>
 425  ---------------------------------------
 426  
 427  The above code produced this example.
 428  
 429  image::images/pyvcp_led.png[]
 430  
 431  .Rectangle LED
 432  
 433  This is a variant of the 'led' widget.
 434  
 435  [source,xml]
 436  -------------------------------------------------
 437  <vbox>
 438      <relief>RIDGE</relief>
 439      <bd>6</bd>
 440      <rectled>
 441          <halpin>"my-led"</halpin>
 442          <height>"50"</height>
 443          <width>"100"</width>
 444          <on_color>"green"</on_color>
 445          <off_color>"red"</off_color>
 446      </rectled>
 447  </vbox>
 448  -------------------------------------------------
 449  
 450  The above code produced this example. 
 451  Also showing a vertical box with relief. 
 452  
 453  image::images/pyvcp_rectled.png[]
 454  
 455  === Buttons
 456  
 457  A button is used to control a BIT pin. The pin will be set True when
 458  the button is pressed and held down, and will be set False when the
 459  button is released. Buttons can use the following optional options.
 460  
 461  * '<padx>n</padx>' - where 'n' is the amount of extra horizontal extra space.
 462  
 463  * '<pady>n</pady>' - where 'n' is the amount of extra vertical extra space.
 464  
 465  * '<activebackground>"color"</activebackground>' - the cursor over color.
 466  
 467  * '<fg> "color"</fg>' - the forground color.
 468  
 469  * '<bg>"color"</bg>' - the background color.
 470  
 471  * '<disable_pin>True</disable_pin>' - disable pin.
 472  
 473  .Text Button
 474  
 475  A text button controls a 'bit' halpin. The halpin is false until the
 476  button is pressed then it is true. The button is a momentary button.
 477  
 478  The text button has an optional disable pin that is created when you
 479  add <disable_pin>True</disable_pin>.
 480  
 481  [source,xml]
 482  ---------------------------------------
 483  <button>
 484      <halpin>"ok-button"</halpin>
 485      <text>"OK"</text>
 486  </button>
 487  <button>
 488      <halpin>"abort-button"</halpin>
 489      <text>"Abort"</text>
 490  </button
 491  ---------------------------------------
 492  
 493  The above code produced this example. 
 494  
 495  image::images/pyvcp_button.png[]
 496  
 497  .Checkbutton
 498  
 499  A checkbutton controls a bit halpin. The halpin will be set True when the
 500  button is checked, and false when the button is unchecked. The checkbutton is a
 501  toggle type button. The Checkbuttons may be set initially as TRUE or FALSE the
 502  initval field A pin called changepin is also created automatically, which can
 503  toggle the Checkbutton via HAL, if the value linked is changed, to update the
 504  display remotely.
 505  
 506  [source,xml]
 507  ---------------------------------------
 508  <checkbutton>
 509      <halpin>"coolant-chkbtn"</halpin>
 510      <text>"Coolant"</text>
 511      <initval>1</initval>
 512  </checkbutton>
 513  <checkbutton>
 514      <halpin>"chip-chkbtn"</halpin>
 515      <text>"Chips    "</text>
 516      <initval>0</initval>
 517  </checkbutton>
 518  ---------------------------------------
 519  
 520  The above code produced this example. 
 521  The coolant checkbutton is checked. 
 522  Notice the extra spaces in the Chips text 
 523  to keep the checkbuttons aligned. 
 524  
 525  image::images/pyvcp_checkbutton.png[]
 526  
 527  .Radiobutton
 528  
 529  A radiobutton will set one of the halpins true. The other pins are set false.
 530  The initval field may be set to choose the default selection when the panel
 531  displays. Only one radio button may be set to TRUE (1) or only the highest
 532  number pin set TRUE will have that value.
 533  
 534  [source,xml]
 535  -------------------------------------------------
 536  <radiobutton>
 537      <choices>["one","two","three"]</choices>
 538      <halpin>"my-radio"</halpin>
 539      <initval>0</initval>
 540  </radiobutton>
 541  -------------------------------------------------
 542  
 543  The above code produced this example. 
 544  
 545  image::images/pyvcp_radiobutton.png[]
 546  
 547  Note that the HAL pins in the example above will be named
 548  my-radio.one, my-radio.two, and my-radio.three. In the image above,
 549  'one' is the selected value.
 550  Use this tag '<orient>HORIZONTAL</orient>' to display horizontally.
 551  
 552  === Number Displays
 553  
 554  Number displays can use the following formatting options
 555  
 556  * <font>("Font Name",n)</font> where 'n' is the font size
 557  * <width>n</width> where 'n' is the overall width of the space used
 558  * <justify>pos</justify> where 'pos' is LEFT, CENTER, or RIGHT (doesn't work)
 559  * <padx>n</padx> where 'n' is the amount of extra horizontal extra space
 560  * <pady>n</pady> where 'n' is the amount of extra vertical extra space
 561  
 562  .Number
 563  
 564  The number widget displays the value of a float signal.
 565  
 566  [source,xml]
 567  ---------------------------------------
 568  <number>
 569      <halpin>"my-number"</halpin>
 570      <font>("Helvetica",24)</font>
 571      <format>"+4.4f"</format>
 572  </number>
 573  --------------------------------------- 
 574  
 575  The above code produced this example.
 576   
 577  image::images/pyvcp_number.png[]
 578  
 579  * '<font>' - is a Tkinter font type and size specification. One font that
 580  will show up to at least size 200 is 'courier 10 pitch', so for a
 581  really big Number widget you could specify:
 582  
 583  [source,xml]
 584  -------------------------------------------------
 585  <font>("courier 10 pitch",100)</font>
 586  -------------------------------------------------
 587  
 588  * '<format>' - is a 'C-style' format specified that determines how
 589  the number is displayed.
 590  
 591  .s32 Number
 592  
 593  The s32 number widget displays the value of a s32 number. The syntax
 594  is the same as 'number' except the name which is <s32>. Make sure the
 595  width is wide enough to cover the largest number you expect to use.
 596  
 597  [source,xml]
 598  -------------------------------------------------
 599  <s32>
 600      <halpin>"my-number"</halpin>
 601      <font>("Helvetica",24)</font>
 602      <format>"6d"</format>
 603      <width>6</width>
 604  </s32>
 605  -------------------------------------------------
 606  
 607  The above code produced this example. 
 608  
 609  image::images/pyvcp_s32.png[]
 610  
 611  .u32 Number
 612  
 613  The u32 number widget displays the value of a u32 number. The syntax
 614  is the same as 'number' except the name which is <u32>.
 615  
 616  .Bar
 617  
 618  A bar widget displays the value of a FLOAT signal both graphically
 619  using a bar display and numerically.
 620  The color of the bar can be set as one color throughout its range (default
 621  using fillcolor) or set to change color dependent upon the value of the halpin
 622  (range1, range2 range3 must all be set, if you only want 2 ranges, set 2 of
 623  them to the same color).
 624  
 625  * <halpin>"my-bar"</halpin> text, sets the pin name, pyvcp.my-bar
 626  * <min_>0</min_> number, sets the minimum scale
 627  * <max_>140</max_> number, sets the maximum scale
 628  * <format>"3.1f"</format> text, sets the number format using python number
 629    formatting
 630  * <bgcolor>"grey"</bgcolor> text, sets the background color
 631  * <fillcolor>"red"</fillcolor> text, sets the fill color
 632  * <range1>0,100,"green"</range1> number, number, text, sets the first range and
 633    color
 634  * <range2>101,135,"orange"</range2> number, number, text, sets the first range
 635    and color
 636  * <range3>136, 150,"red"</range3> number, number, text, sets the first range and
 637    color
 638  * <canvas_width>200</canvas_width> number, sets the overall width
 639  * <canvas_height>50</canvas_height> number, sets the overall height
 640  * <bar_height>30</bar_height> number, sets the bar height, must be less than
 641    canvas_height
 642  * <bar_width>150</bar_width> number, sets the bar width, must be less than
 643    canvas_width
 644  
 645  [source,xml]
 646  ---------------------------------------
 647  <bar>
 648      <halpin>"my-bar"</halpin>
 649      <min_>0</min_>
 650      <max_>123</max_>
 651      <format>"3.1f"</format>
 652      <bgcolor>"grey"</bgcolor>
 653      <fillcolor>"red"</fillcolor>
 654      <range1>0,100,"green"</range1>
 655      <range2>101,135,"orange"</range2>
 656      <range3>136, 150,"red"</range3>
 657      <canvas_width>200</canvas_width>
 658      <canvas_height>50</canvas_height>
 659      <bar_height>30</bar_height>
 660      <bar_width>150</bar_width>
 661  </bar>
 662  ---------------------------------------
 663  
 664  The above code produced this example. 
 665  
 666  image::images/pyvcp_bar.png[]
 667  
 668  .Meter
 669  
 670  Meter displays the value of a FLOAT signal using a traditional dial indicator.
 671  
 672  [source,xml]
 673  -------------------------------------------------
 674  <meter>
 675      <halpin>"mymeter"</halpin>
 676      <text>"Battery"</text>
 677      <subtext>"Volts"</subtext>
 678      <size>250</size>
 679      <min_>0</min_>
 680      <max_>15.5</max_>
 681      <majorscale>1</majorscale>
 682      <minorscale>0.2</minorscale>
 683      <region1>(14.5,15.5,"yellow")</region1>
 684      <region2>(12,14.5,"green")</region2>
 685      <region3>(0,12,"red")</region3>
 686  </meter>
 687  -------------------------------------------------
 688  
 689  The above code produced this example. 
 690  
 691  image::images/pyvcp_meter.png[]
 692  
 693  === Number Inputs
 694  
 695  .Spinbox
 696  
 697  Spinbox controls a FLOAT pin. You increase or decrease the value of the pin by
 698  either pressing on the arrows, or pointing at the spinbox and rolling your
 699  mouse-wheel. If the param_pin field is set TRUE(1), a pin will be created that
 700  can be used to set the spinbox to an initial value and to remotely alter its
 701  value without HID input.
 702  
 703  [source,xml]
 704  ---------------------------------------
 705  <spinbox>
 706      <halpin>"my-spinbox"</halpin>
 707      <min_>-12</min_>
 708      <max_>33</max_>
 709      <initval>0</initval>
 710      <resolution>0.1</resolution>
 711      <format>"2.3f"</format>
 712      <font>("Arial",30)</font>
 713      <param_pin>1</param_pin>
 714  </spinbox>
 715  ---------------------------------------
 716  
 717  The above code produced this example. 
 718  
 719  image::images/pyvcp_spinbox.png[]
 720  
 721  .Scale
 722  
 723  Scale controls a float or a s32 pin. You increase or decrease the
 724  value of the pin be either dragging the slider, or pointing at the
 725  scale and rolling your mouse-wheel. The 'halpin' will have both '-f'
 726  and '-i' added to it to form the float and s32 pins. Width is the width
 727  of the slider in vertical and the height of the slider in horizontal
 728  orientation. If the param_pin field is set TRUE(1), a pin will be created that
 729  can be used to set the spinbox to an initial value and to remotely alter its
 730  value without HID input.
 731  
 732  
 733  [source,xml]
 734  ---------------------------------------
 735  <scale>
 736      <font>("Helvetica",16)</font>
 737      <width>"25"</width>
 738      <halpin>"my-hscale"</halpin>
 739      <resolution>0.1</resolution>
 740      <orient>HORIZONTAL</orient>
 741      <initval>-15</initval>
 742      <min_>-33</min_>
 743      <max_>26</max_>
 744      <param_pin>1</param_pin>
 745  </scale>
 746  <scale>
 747      <font>("Helvetica",16)</font>
 748      <width>"50"</width>
 749      <halpin>"my-vscale"</halpin>
 750      <resolution>1</resolution>
 751      <orient>VERTICAL</orient>
 752      <min_>100</min_>
 753      <max_>0</max_>
 754      <param_pin>1</param_pin>
 755  </scale>
 756  ---------------------------------------
 757  
 758  The above code produced this example.
 759  
 760  image::images/pyvcp_scale.png[]
 761  
 762  .Dial
 763  
 764  The Dial outputs a HAL float and reacts to both mouse wheel and
 765  dragging. Double left click to increase the resolution and double right
 766  click to reduce the resolution by one digit. The output is capped by
 767  the min and max values. The <cpr> is how many tick marks are on the
 768  outside of the ring (beware of high numbers). If the param_pin field is set
 769  TRUE(1), a pin will be created that can be used to set the spinbox to
 770  an initial value and to remotely alter its value without HID input.
 771  
 772  [source,xml]
 773  ---------------------------------------
 774  <dial>
 775      <size>200</size>
 776      <cpr>100</cpr>
 777      <min_>-15</min_>
 778      <max_>15</max_>
 779      <text>"Dial"</text>
 780      <initval>0</initval>
 781      <resolution>0.001</resolution>
 782      <halpin>"anaout"</halpin>
 783      <dialcolor>"yellow"</dialcolor>
 784      <edgecolor>"green"</edgecolor>
 785      <dotcolor>"black"</dotcolor>
 786      <param_pin>1</param_pin>
 787  </dial>
 788  ---------------------------------------
 789  
 790  The above code produced this example.
 791  
 792  image::images/pyvcp_dial.png[]
 793  
 794  .Jogwheel
 795  
 796  Jogwheel mimics a real jogwheel by outputting a FLOAT pin which counts
 797  up or down as the wheel is turned, either by dragging in a circular
 798  motion, or by rolling the mouse-wheel.
 799  
 800  [source,xml]
 801  ---------------------------------------
 802  <jogwheel>
 803      <halpin>"my-wheel"</halpin>
 804      <cpr>45</cpr>
 805      <size>250</size>
 806  </jogwheel>
 807  ---------------------------------------
 808  
 809  The above code produced this example.
 810  
 811  image::images/pyvcp_jogwheel.png[]
 812  
 813  === Images
 814  
 815  Image displays use only .gif image format. All of the images must be
 816  the same size. The images must be in the same directory as your ini
 817  file (or in the current directory if running from the command line with
 818  halrun/halcmd).
 819  
 820  .Image Bit
 821  
 822  The 'image_bit' toggles between two images by setting the halpin to
 823  true or false.
 824  
 825  [source,xml]
 826  -----------------------------------------------------------
 827  <image name='fwd' file='fwd.gif'/>
 828  <image name='rev' file='rev.gif'/>
 829  <vbox>
 830      <image_bit halpin='selectimage' images='fwd rev'/>
 831  </vbox>
 832  -----------------------------------------------------------
 833  
 834  This example was produced from the above code.
 835  Using the two image files fwd.gif and rev.gif.
 836  FWD is displayed when 'selectimage' is false
 837  and REV is displayed when 'selectimage' is true.
 838  
 839  image:images/pyvcp_image01.png[] image:images/pyvcp_image02.png[]
 840  
 841  .Image u32
 842  
 843  The 'image_u32' is the same as 'image_bit' except you have essentially
 844  an unlimited number of images and you 'select' the image by setting the
 845  halpin to a integer value with 0 for the first image in the images list
 846  and 1 for the second image etc.
 847  
 848  [source,xml]
 849  ---------------------------------------------------------------------
 850  <image name='stb' file='stb.gif'/>
 851  <image name='fwd' file='fwd.gif'/>
 852  <image name='rev' file='rev.gif'/>
 853  <vbox>
 854      <image_u32 halpin='selectimage' images='stb fwd rev'/>
 855  </vbox>
 856  ---------------------------------------------------------------------
 857  
 858  The above code produced the following example
 859  by adding the stb.gif image.
 860  
 861  image:images/pyvcp_image_u32_01.png[]
 862  image:images/pyvcp_image01.png[]
 863  image:images/pyvcp_image02.png[]
 864  
 865  Notice that the default is the min even though it is set higher than
 866  max unless there is a negative min.
 867  
 868  === Containers
 869  
 870  Containers are widgets that contain other widgets. Containers are used
 871  to group other widgets.
 872  
 873  .Borders
 874  
 875  Container borders are specified with two tags used together. The
 876  <relief> tag specifies the type of border and the <bd> specifies the
 877  width of the border.
 878  
 879  * '<relief>type</relief>' -
 880      Where 'type' is FLAT, SUNKEN, RAISED, GROOVE, or RIDGE
 881  
 882  * '<bd>n</bd>' - 
 883      Where 'n' is the width of the border.
 884  
 885  [source,xml]
 886  ----
 887  <hbox>
 888      <button>
 889          <relief>FLAT</relief>
 890          <text>"FLAT"</text>
 891          <bd>3</bd>
 892      </button>
 893      <button>
 894          <relief>SUNKEN</relief>
 895          <text>"SUNKEN"</text>
 896          <bd>3</bd>
 897      </button>
 898      <button>
 899          <relief>RAISED</relief>
 900          <text>"RAISED"</text>
 901          <bd>3</bd>
 902      </button>
 903      <button>
 904          <relief>GROOVE</relief>
 905          <text>"GROOVE"</text>
 906          <bd>3</bd>
 907      </button>
 908      <button>
 909          <relief>RIDGE</relief>
 910          <text>"RIDGE"</text>
 911          <bd>3</bd>
 912      </button>
 913  </hbox>
 914  ----
 915  
 916  The above code produced this example.
 917  
 918  image::images/pyvcp_borders.png[]
 919  
 920  
 921  .Fill
 922  
 923  Container fill are specified with the '<boxfill fill=""/>' tag. Valid entries
 924  are none, x, y and both. The x fill is a horizontal fill and the y fill is a 
 925  vertical fill
 926  
 927  * '<boxfill fill ="style"/>' - 
 928      Where 'style' is none, x, y, or both. Default is x for Vbox and y for Hbox.
 929  
 930  .Anchor
 931  
 932  Container anchors are specificed with the <boxanchor anchor=""/> tag. The anchor
 933  specifies where to position each slave in its parcel. Valid entries are center,
 934  n, s, e, w, for center, north, south, east and west. Combinations like sw, se,
 935  nw and ne are also valid.
 936  
 937  * '<boxanchor anchor="position"/>' -
 938      Where 'position' is center, n, s, e, w, ne, nw, se or sw. Default is center.
 939  
 940  .Expand
 941  
 942  Container expand is specificed with the boolean <boxexpand expand=""/> tag.
 943  Valid entries are yes, no.
 944  
 945  * '<boxexpand expand="boolean"/>' -
 946      Where 'boolean' is either yes or no. Default is yes.
 947  
 948  .Hbox
 949  
 950  Use an Hbox when you want to stack widgets horizontally
 951  next to each other.
 952  
 953  [source,xml]
 954  -------------------------------------------------
 955  <hbox>
 956      <relief>RIDGE</relief>
 957      <bd>6</bd>
 958      <label><text>"a hbox:"</text></label>
 959      <led></led>
 960      <number></number>
 961      <bar></bar>
 962  </hbox>
 963  -------------------------------------------------
 964  
 965  The above code produced this example.
 966  
 967  image::images/pyvcp_hbox.png[]
 968  
 969  Inside an Hbox, you can use the '<boxfill fill=""/>', '<boxanchor anchor=""/>'
 970  , and '<boxexpand expand=""/>' tags to choose how items in the box behave when
 971  the window is re-sized.The default is 'fill="y"', 'anchor="center"', 'expand="yes"'
 972  for a Hbox.
 973  
 974  .Vbox
 975  
 976  Use a Vbox when you want to stack widgets vertically on top of each
 977  other.
 978  
 979  [source,xml]
 980  -------------------------------------------------
 981  <vbox>
 982      <relief>RIDGE</relief>
 983      <bd>6</bd>
 984      <label><text>"a vbox:"</text></label>
 985      <led></led>
 986      <number></number>
 987      <bar></bar>
 988  </vbox>
 989  -------------------------------------------------
 990  
 991  The above code produced this example.
 992  
 993  image::images/pyvcp_vbox.png[]
 994  
 995  Inside a Vbox, you can use the '<boxfill fill=""/>', '<boxanchor anchor=""/>'
 996  , and '<boxexpand expand=""/>' tags to choose how items in the box behave
 997  when the window is re-sized. The default is 'fill="x"', 'anchor="center"',
 998  'expand="yes"' for a Hbox.
 999  
1000  .Labelframe
1001  
1002  A labelframe is a frame with a groove and a label at the upper-left
1003  corner.
1004  
1005  [source,xml]
1006  ---------------------------------------
1007  <labelframe text="Group Title">
1008      <font>("Helvetica",16)</font>
1009      <hbox>
1010      <led/>
1011      <led/>
1012      </hbox>
1013  </labelframe>
1014  ---------------------------------------
1015  
1016  The above code produced this example.
1017  
1018  image::images/pyvcp_labelframe.png[]
1019  
1020  .Table
1021  
1022  A table is a container that allows layout in a grid of rows and
1023  columns. Each row is started by a '<tablerow/>' tag. A contained
1024  widget may span rows or columns through the use of
1025  the '<tablespan rows= cols=/>' tag. The sides of the cells to which
1026  the contained widgets “stick”
1027  may be set through the use of the '<tablesticky sticky=/>' tag. A
1028  table expands on its flexible rows and columns.
1029  
1030  Example:
1031  [source,xml]
1032  -----------------------------------------------------------
1033  <table flexible_rows="[2]" flexible_columns="[1,4]">
1034  <tablesticky sticky="new"/>
1035  <tablerow/>
1036      <label>
1037          <text>" A (cell 1,1) "</text>
1038          <relief>RIDGE</relief>
1039          <bd>3</bd>
1040      </label>
1041      <label text="B (cell 1,2)"/>
1042      <tablespan columns="2"/>
1043      <label text="C, D (cells 1,3 and 1,4)"/>
1044  <tablerow/>
1045      <label text="E (cell 2,1)"/>
1046      <tablesticky sticky="nsew"/>
1047      <tablespan rows="2"/>
1048      <label text="'spans\n2 rows'"/>
1049      <tablesticky sticky="new"/>
1050      <label text="G (cell 2,3)"/>
1051      <label text="H (cell 2,4)"/>
1052  <tablerow/>
1053      <label text="J (cell 3,1)"/>
1054      <label text="K (cell 3,2)"/>
1055      <u32 halpin="test"/>
1056  </table>
1057  -----------------------------------------------------------
1058  
1059  The above code produced this example.
1060  
1061  image::images/pyvcp_table.png[]
1062  
1063  .Tabs
1064  
1065  A tabbed interface can save quite a bit of space.
1066  
1067  [source,xml]
1068  -----------------------------------------------------------
1069  <tabs>
1070      <names> ["spindle","green eggs"]</names>
1071  </tabs>
1072  <tabs>
1073      <names>["Spindle", "Green Eggs", "Ham"]</names>
1074      <vbox>
1075          <label>
1076              <text>"Spindle speed:"</text>
1077          </label>
1078          <bar>
1079              <halpin>"spindle-speed"</halpin>
1080              <max_>5000</max_>
1081          </bar>
1082      </vbox>
1083      <vbox>
1084          <label>
1085              <text>"(this is the green eggs tab)"</text>
1086          </label>
1087      </vbox>
1088      <vbox>
1089          <label>
1090              <text>"(this tab has nothing on it)"</text>
1091          </label>
1092      </vbox>
1093  </tabs>
1094  -----------------------------------------------------------
1095  
1096  The above code produced this example showing each tab selected.
1097  
1098  image::images/pyvcp_tabs1.png[]
1099  
1100  image::images/pyvcp_tabs2.png[]
1101  
1102  image::images/pyvcp_tabs3.png[]
1103  
1104