216 lines
8.7 KiB
Python
216 lines
8.7 KiB
Python
#!/usr/bin/env python3
|
|
# vim: sts=4 sw=4 et
|
|
# This is a component of LinuxCNC
|
|
# complex.py Copyright 2010 Michael Haberler
|
|
#
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.''''''
|
|
'''
|
|
gladevcp complex demo example
|
|
Michael Haberler 11/2010
|
|
|
|
'''
|
|
|
|
import os,sys
|
|
from gladevcp.persistence import IniFile,widget_defaults,set_debug,select_widgets
|
|
import hal
|
|
import hal_glib
|
|
import gtk
|
|
|
|
import gi
|
|
from gi.repository import GLib
|
|
|
|
debug = 0
|
|
|
|
class HandlerClass:
|
|
'''
|
|
class with gladevcp callback handlers
|
|
'''
|
|
|
|
def on_button_press(self,halwidget,data=None):
|
|
'''
|
|
a callback method
|
|
parameters are:
|
|
the generating object instance, like a GtkButton instance
|
|
user data passed if any - this is currently unused but
|
|
the convention should be retained just in case
|
|
'''
|
|
print("on_button_press()")
|
|
self.nhits += 1
|
|
halwidget.set_label("hits: %d" % self.nhits)
|
|
|
|
|
|
def on_toggle_button(self,hal_button,data=None):
|
|
'''
|
|
standard button-pressed callback. Parameter is the widget object instance.
|
|
'''
|
|
print("on_toggle_button() HAL pin value: %s" %(str(hal_button.hal_pin.get())))
|
|
|
|
def _on_example_trigger_change(self,hal_pin,data=None):
|
|
'''
|
|
executed when the 'example-trigger' hal pin value changes
|
|
note that this callback will not be exposed as potential callback
|
|
handler through gladevcp since the name begins with an underscore (_) .
|
|
Parameter is the HAL pin instance.
|
|
'''
|
|
print("_on_example_trigger_change() - HAL pin value: %s" % (hal_pin.get()))
|
|
|
|
def on_led_pin_changed(self,hal_led,data=None):
|
|
'''
|
|
this is an example of a hal-pin-changed signal handler as set in glade.
|
|
The purpose of this callback is to deliver an optional notification to your code beyond
|
|
just reacting to the changed HAL pin.
|
|
the on_led_pin_changed signal is set in the complex.ui hal_led1 signals section
|
|
'''
|
|
print("on_led_pin_changed() - HAL pin value:",hal_led.hal_pin.get())
|
|
|
|
def _on_timer_tick(self,userdata=None):
|
|
'''
|
|
the full glib functionality is available if needed.
|
|
here's a timer function which will be called periodically
|
|
returning True restarts the timer
|
|
returning False makes it a one-shot
|
|
'''
|
|
self.lifetime_ticks += 1
|
|
self.builder.get_object('message').hal_pin.set(self.lifetime_ticks)
|
|
return True
|
|
|
|
|
|
def on_unix_signal(self,signum,stack_frame):
|
|
print("on_unix_signal(): signal %d received, saving state" % (signum))
|
|
self.ini.save_state(self)
|
|
gtk.main_quit()
|
|
self.halcomp.exit()
|
|
|
|
def on_destroy(self,obj,data=None):
|
|
'''
|
|
gladevcp_demo.ui has a destroy callback set in the window1 Gobject
|
|
note the widget tree is not safely accessible here any more
|
|
'''
|
|
print("on_destroy() - saving state)")
|
|
self.ini.save_state(self)
|
|
|
|
def on_restore_defaults(self,button,data=None):
|
|
self.ini.create_default_ini()
|
|
self.ini.restore_state(self)
|
|
self.builder.get_object('hal_button1').set_label("past hits: %d" % self.nhits)
|
|
|
|
def on_save_settings(self,button,data=None):
|
|
print("on_save_settings() - saving state")
|
|
self.ini.save_state(self)
|
|
|
|
def _hal_setup(self,halcomp, builder):
|
|
'''
|
|
hal related initialisation
|
|
'''
|
|
|
|
# the toplevel window is always named 'window1'. Do not change.
|
|
# widgets may be accessed through builder.get_object() and
|
|
# builder.get_objects()
|
|
self.window1 = self.builder.get_object("window1")
|
|
self.led1 = self.builder.get_object("hal_led1")
|
|
|
|
# standard hal pins not associated with any widget
|
|
self.halcomp.newpin("example-out", hal.HAL_BIT, hal.HAL_OUT)
|
|
self.halcomp.newpin("example-in", hal.HAL_S32, hal.HAL_IN)
|
|
|
|
# hal pins with change callback. Also unrelated to any HAL widget.
|
|
# When the pin's value changes the callback is executed.
|
|
self.example_trigger = hal_glib.GPin(halcomp.newpin('example-trigger', hal.HAL_BIT, hal.HAL_IN))
|
|
self.example_trigger.connect('value-changed', self._on_example_trigger_change)
|
|
|
|
def __init__(self, halcomp,builder,useropts):
|
|
'''
|
|
Handler classes are instantiated in the following state:
|
|
- the widget tree is created, but not yet realized (no toplevel window.show() executed yet)
|
|
- the halcomp HAL component is set up and the widhget tree's HAL pins have already been added to it
|
|
- it is safe to add more hal pins because halcomp.ready() has not yet been called at this point.
|
|
|
|
after all handlers are instantiated in command line and get_handlers() order, callbacks will be
|
|
connected with connect_signals()/signal_autoconnect()
|
|
|
|
The builder may be either of libglade or GtkBuilder type depending on the glade file format.
|
|
'''
|
|
self.halcomp = halcomp
|
|
self.builder = builder
|
|
|
|
(directory,filename) = os.path.split(__file__)
|
|
(basename,extension) = os.path.splitext(filename)
|
|
self.ini_filename = os.path.join(directory,basename + '.save')
|
|
|
|
# the dict driving the ini file persistence feature
|
|
# a signature checks variable names,types,sections
|
|
#
|
|
# to see the mechanism at work, do this:
|
|
# - run the application, change some values, and exit
|
|
# - edit the complex.save file and change a variable name in the widgets or vars section
|
|
# for example, rename 'a' to 'z'
|
|
# and remove one of the widgets in the widgets section
|
|
# - then re-run the application
|
|
# during startup, you get a message saying
|
|
# "key 'a' in section 'vars' : missing"
|
|
# "key 'hal_radiobutton1' in section 'widgets' : missing"
|
|
#
|
|
# to see how the protection of ini file versus a changed program works,
|
|
# change the defaults dict below, for instance remove the 'c' : "a string variable
|
|
# then re-run - the signature check at startup should fail, you should get:
|
|
# "signature mismatch in ./complex.save - resetting to default"
|
|
# and a default ini file is generated
|
|
|
|
self.defaults = { # these will be saved/restored as method attributes
|
|
IniFile.vars: { 'nhits' : 0, 'lifetime_ticks': 0, 'a': 1.67, 'd': True, 'c' : "a string"},
|
|
|
|
# we're interested restoring state to output HAL widgets only
|
|
# NB: this does NOT restore state pf plain gtk objects - set hal_only to False to do this
|
|
IniFile.widgets: widget_defaults(select_widgets(self.builder.get_objects(), hal_only=True,output_only = True)),
|
|
}
|
|
|
|
self.ini = IniFile(self.ini_filename,self.defaults, self.builder)
|
|
self.ini.restore_state(self)
|
|
|
|
# at this point it is ok to refer to restored attributes like self.nhits and self.lifetime_ticks:
|
|
self.builder.get_object('hal_button1').set_label("past hits: %d" % self.nhits)
|
|
self.builder.get_object('message').hal_pin.set(self.lifetime_ticks)
|
|
|
|
self._hal_setup(halcomp,builder)
|
|
|
|
# demonstrate a slow background timer - granularity is one second
|
|
# for a faster timer, use this:
|
|
# GLib.timeout_add(5000, self._on_timer_tick)
|
|
GLib.timeout_add_seconds(1, self._on_timer_tick)
|
|
|
|
|
|
def get_handlers(halcomp,builder,useropts):
|
|
'''
|
|
this function is called by gladevcp at import time (when this module is passed with '-u <modname>.py')
|
|
|
|
return a list of object instances whose methods should be connected as callback handlers
|
|
any method whose name does not begin with an underscore ('_') is a callback candidate
|
|
|
|
the 'get_handlers' name is reserved - gladevcp expects it, so do not change
|
|
'''
|
|
|
|
# try this at command line:
|
|
# -U debug=42 -U "print 'debug=%d' % debug"
|
|
global debug
|
|
for cmd in useropts:
|
|
exec(cmd, globals())
|
|
|
|
set_debug(debug)
|
|
|
|
if debug: print("%s.get_handlers() called" % (__name__))
|
|
|
|
return [HandlerClass(halcomp,builder,useropts)]
|