10.4  Using Controls

by Martin Grimme

10.4.1  Introduction

Controls let your inline scripts access any kind of data. They are easy-to-use sharable modules which provide you with more power. In this tutorial we are going to make a digital clock with timezone support which uses a time control for telling the time.

10.4.2  Browsing Controls

Before you can use a control (unless you write it yourself), you have to find it. The gdesklets-shell lets you browse all the controls which are installed on your system.

Select the Controls view to enter the controls browser. There you can, for example, choose the alphabetical list for searching for a certain control.

For this tutorial, we're interested in a control for reading the current time. So we look under "T" for "Time".

10.4.3  Inspecting Controls

Now that you have found the control, you can learn more about it by inspecting its properties. To open the controls inspector, just double click on the control in the list on the right side of the window.

The controls inspector lists all available properties of the control together with their access permissions and a short description. Each control has a set of properties with which it can be configured and from which you can read information.

Our time control, for example, provides a time property for reading the current time. There are other properties available as well, but for now, we're just interested in that time property.

The "r" permission shown for the time property means that this property can only be read. It cannot be written. This makes sense, because you can only read the time, but not change it.

10.4.4  Loading Controls

Before you can use a control, you have to load it first. If you took a closer look at the control browser, you could see that every control implements one or more interfaces, which define the set of available properties. So two different controls implementing the same interfaces would be perfectly interchangable.

Every interface has a unique identifier by which you can load controls. The identifier is displayed by the controls inspector and can be copied and pasted from there into your text editor.

To load a control in your .display you specify this ID in the <control> tag. This tag has a property interface for the interface ID. A compatible control is then looked up by searching for that interface. The other property id specifies the identifier by which you can access that control in the scripts.

<display window-flags="sticky, below">

  <control id="mytime" interface="ITime:9y703dqtfnv4w373caserz68r"/>

</display>
  

To avoid any mistakes, just copy and paste the interface ID from the controls inspector.

Of course, there is no limitation in the number of controls used in a .display file. You can have as many <control> tags as you like.

10.4.5  Accessing the Control

The loaded control is an object with properties, which you can access in the scripts.

<script>

  print "The current time is:"
  print mytime.time

</script>
  

The time property of our time control returns the current time as a triple of integers for hours, minutes, and seconds.

<script>

  h, m, s = mytime.time
  print "The current time is:"
  print "%2d:%2d.%2d" % (h, m, s)

</script>
  

Instead of printing out the values, we can also write them into a label.

<display window-flags="sticky, below">

  <control id="mytime" interface="ITime:9y703dqtfnv4w373caserz68r"/>

  <label id="mylabel" font="Mono 1cm" color="red"/>

  <script><![CDATA[

    h, m, s = mytime.time
    Dsp.mylabel.value = "%2d:%2d.%2d" % (h, m, s)

  ]]></script>

</display>
  

Congratulations to your first controls-based applet!

10.4.6  Making the Clock Run

We have a clock applet so far, but still, the clock doesn't update its time. Such a clock would show the correct time once a day, but we can make it better.

The time property always contains the current time, so we could continually poll the time from there by setting up a timer.

def timer():

    h, m, s = mytime.time
    Dsp.mylabel.value = "%2d:%2d.%2d" % (h, m, s)
    return True

# call the timer every 1000ms = 1s
add_timer(1000, timer)
  

While this would work, it's not really good programming. Instead of continually reading the property, we can watch it and receive notifications only when it actually changes.

A property can be watched by binding a watching handler to it. Not all properties support this, however, because it doesn't make sense always. Our time property supports watching, so that we can bind a handler to the property via the bind(name, handler) method of the control.

def myhandler(new_value):

    h, m, s = new_value
    Dsp.mylabel.value = "%2d:%2d.%2d" % (h, m, s)

mytime.bind("time", myhandler)
  

In the example above, we are binding the function myhandler to the time of the control. Whenever the time property changes its value (once a second, of course), our handler will be invoked with the new value as its argument.

<display window-flags="sticky, below">

  <control id="mytime" interface="ITime:9y703dqtfnv4w373caserz68r"/>

  <label id="mylabel" font="Mono 1cm" color="red"/>

  <script><![CDATA[

    def myhandler(new_value):
    
        h, m, s = new_value
        Dsp.mylabel.value = "%2d:%2d.%2d" % (h, m, s)

    mytime.bind("time", myhandler)

  ]]></script>

</display>
  

Run this example and you will see that the clock now updates its time correctly.

The bind method is available for every control. Properties which don't support watching won't call the watching handler, though.

10.4.7  Saving Configuration across Sessions

Controls can be configured by setting their property values. Our time control, for example, can be set to a different time zone by setting its timezone property.

mytime.timezone = "Asia/Tokyo"
  

By using the preferences system, you can make this property user-configurable and save its value across sessions. The timezone property contains a string. Thus we can bind it to a <string> setting in the preferences dialog.

<display window-flags="sticky, below">

  <control id="mytime" interface="ITime:9y703dqtfnv4w373caserz68r"/>

  <label id="mylabel" font="Mono 1cm" color="red"/>


  <prefs>

    <string label="Timezone:" bind="mytime.timezone"/>

  </prefs>


  <script><![CDATA[

    def myhandler(new_value):
    
        h, m, s = new_value
        Dsp.mylabel.value = "%2d:%2d.%2d" % (h, m, s)

    mytime.bind("time", myhandler)

  ]]></script>

</display>