:lang: en
:toc:

[[cha:qtvcp-development]]
= QTvcp Development

The intention of QtVCP is to supply an infrastructure to support
screen and VCP panel building for linuxcnc. By supplying a diverse
widget set and supporting custom coding, QtVCP hopes that development
energy will be expended in one toolkit rather then continuous re-invention.
By using the same toolkit across many screens/panels users should have an easier
time customizing/creating and developers should find it easier to help
trouble shoot with less effort.

== Overview

QtVCP uses a QT Designer built .ui file and a python handler file
to load and control a screen/panel that displays QT widgets to control
linuxcnc's motion controller or HAL pins.
There are builtin screens and panels, easily loaded by a user or
A user can build/modify one of their own.
QtVCP uses libraries and custom widgets to hide some of the complexity
of interfacing to linuxcnc. By using QtVCP's library rather then linuxcnc's,
We can mitigate minor linuxcnc code changes.

== Builtin locations

Builtin screens and panels are stored in separate folders.

* screens in share/qtvcp/screens
* panels in share/qtvcp/panels
* Stock images are in share/qtvcp/images

screens and panels are sorted by their folder name, which is
also the name used to load them.
Inside the folder would be the .ui file, the handler file and
possibly the .qss theme file.

== QtVCP startup to shutdown

QtVCP source is located in src/emc/usr_intf/qtvcp

* When QtVCP first starts, it must decide if this object is a screen
  or a panel. Then it searches for and collects information about
  paths of required files and useful folders.
* Next, it builds the HAL component, loads the window instance,
  adds handler extensions and installs an event filter.
* Now the window/widgets are instantiated, the HAL pins are built,
  which also initiates the '_init_hal()' function of the widgets.
* The handler function 'initialized__()' is called and then the STATUS
  library is forced to update. Hal component is set ready at this point.
* A variety of optional switch arguments are set, including calling a
  POSTGUI HAL file (if a screen). Terminate signals are trapped and
  QtVCP now polls for events.
* Finally when QtVCP is asked to shutdown, it calls shutdown functions
  in the handler file, shuts down STATUS monitoring and kills the HAL
  component.

== Path information

When QtVCP loads it collects Path information:
This is available in the handler file's '__init__()' function
as 'path'

* IMAGEDIR = Path of builtin images
* SCREENDIR = Path of builtin motion controller screens + 
* PANELDIR = Path of builtin accessory panels
* WORKINGDIR = Path of where QtVCP was launched from
* CONFIGPATH = Path of the launched configuration
* BASEDIR = general path, used to derive all paths
* BASENAME = Generic name used to derive all paths + 
* LIBDIR = Path of QtVCP's python library
* HANDLER = Path of handler file
* XML = Path of .ui file
* DOMAIN = Path of translation
* IS_SCREEN = screen/panel switch

== Idiosyncrasies

These try to cover non-obvious situations.

=== Error code  collecting

Linuxcnc's error code collecting can only be read from one place.
When read , it is 'consumed' - no other object can read it.
In QtVCP screens, it is recommended to use the ScreenOptionss widget to
set up error reading. They are then sent to other objects via STATUS
signals.

=== Jog rate

Linuxcnc has no internal record of jog rate - you must specify it at the
time of jogging.
QtVCP uses the STATUS library to keep track of the latest linear and
angular jog rate. It is always specified in machine units per minute, so must be
converted when in non-machine units mode.
So if your machine is imperial based but you are in metric mode
changes to jog rate sent to ACTION functions must be converted to imperial.
at the same time if the machine is metric based and you are in imperial mode,
 changes to jog rate must be sent to ACTION functions in metric units.
Angular jog rates the units don't change in metric/imperial
mode so you can send them to ACTION functions without conversion.
While you are free to ignore this jogging record while building screens,
Anyone modifying your screen and using the builtin jog rate widgets would
not get the desired results. The ACTION library's 'DO_JOG' function, gets
it's jog rate from the STATUS library.

=== Keybinding

Keybinding is always a difficult-to-get-right-in-all-cases affair.
Custom keybinding functions are to be defined in the handler file.
Most importantly widgets that require regular key input and not jogging,
should be checked for in the 'processed_key_event__' function.

=== Preference file

Some QtVCP widget use the preference file to record important information.
This requires The preference file to be set up early in the widget
initialization process. The easiest way to do this is to use the
ScreenOptions widget.

=== Widget special setup functions

QtVCP looks for and calls the '_hal_init' function, when the widget
is first loaded. It is not called when using Designer editor.
After this function is called the widget has access to some special
variables:

[source,python]
----
self.HAL_GCOMP = the HAL component instance
self.HAL_NAME = This widgets name as a string
self.QT_OBJECT_ = This widgets pyQt object instance
self.QTVCP_INSTANCE_ = The very toplevel Parent Of the screen
self.PATHS_ = The instance of QtVCP's path library
self.PREFS_ = the instance of an optional preference file
self.SETTINGS_ = the Qsettings object
----

When making a custom widget, import and sub class the
'_HalWidgetBase' class for this behavior:

=== Dialogs

Dialogs (AKA pop up windows) are best loaded with the screenoptions widget,
but they can be placed on the screen in Designer.
It doesn't matter where on the layout but to make them hidden,
cycle the 'state' property to true then false.

By default, if there is a preference file, the dialogs will
remember their last size/placement. It is possible to override
this so they open in the same location each time.

=== Styles (Themes)

While it is possible to set styles in designer, it is more
convenient to change them later if they are all set in a
separate .qss file. The file should be put in the same
location as the handler file.

// vim: set syntax=asciidoc:
