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