# OcempGUI Manual

Marcus von Appen

`<marcus@sysfault.org>`

Copyright © 2005-2007 Marcus von Appen

Redistribution and use in source (XML DocBook) and 'compiled' forms (SGML, HTML, PDF, PostScript, RTF and so forth) with or without modification, are permitted provided that the following conditions are met:

1. Redistributions of source code (XML DocBook) must retain the above copyright notice, this list of conditions and the following disclaimer as the first lines of this file unmodified.

2. Redistributions in compiled form (transformed to other DTDs, converted to PDF, PostScript, RTF and other formats) must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

Important: THIS DOCUMENTATION IS PROVIDED BY THE OCEMPGUI PROJECT "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OCEMPGUI PROJECT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Abstract

A GUI library for Pygame

## Preface

This manual gives an overview about the OcempGUI library and explains how to install, configure and use it. It is meant to be an introduction into the OcempGUI library. This manual is not an API reference. Instead the most classes, methods and functions of the OcempGUI library will be briefly described and examples about how to use them will be provided.

### Note

The descriptions, mentioned classes, methods and functions as well as the examples may get out of date and thus using any portion or information of this manual could crash your application or behave in another unexpected way. Although the author tries to keep the manual in synchronization with changes in the library, this can happen from time to time.

If you experience such a misbehaviour or are unsure about a description, refer to the extensive inline documentations of the library. You can accomplish this easily using the pydoc application, for example.

## Introduction

The first versions of OcempGUI were created in 2004, when the author of the package started the Ocean Empire project. Ocean Empire is a reimplementation of an old MS-DOS™ game named Ocean Trader.

The author decided to use the pygame library, which is a python wrapper of the SDL library and noted later, that no matching GUI like extensions exist for it. The first task was to implement such a GUI extension to have a suitable graphical environment for the game. The result of this attempt is OcempGUI.

OcempGUIs focus lies on a GUI toolkit implementation based on the Sprite concept of pygame and is completely implemented in Python. It can be easily integrated in projects and reduces the development time by providing an own event mangement system and a reliable collection of user interface elements, of which all components are easy to use, extensible and support styling for the look and feel.

Besides GUI functionality OcempGUI offers modules for other needs such as accessibility and a fast event management system. Both parts do not need rely on pygame and thus can be used in any Python project.

## Installing OcempGUI

This section describes the process to configure and install OcempGUI.

### Dependencies

The following applications and libraries are needed before OcempGUI can be installed:

- Python, version 2.3 or higher

- pygame, version 1.7.1 or higher

- ATK, version 1.12.1 or higher (optional)

Please refer to the documentation of the respective package about how to install it.

### Binary packages

OcempGUI is not provided as binary package by the author. However it might be that someone else set up such a package for your wanted operating system or distribution. Those packages are usually not supported by the author, what means that installation problems or similar issues, which do not target the library directly, should be escalated to the respective supplier of that package.

### Building from source

The unpacked package contains two possibilities of building and installing it. Both ways are mostly identical but the one or other user might tend to prefer a specific way. The first is the python way of installing software, the second follows the tradition of the unix environment and uses a Makefile (which actually simply starts the python way). While being in the top source directory, it is possible to type either

    make install

for the traditional unix way or

    python setup.py install

for the python way.

The package might have some special options, which are described in the README file shipped with it.

### Using CVS

Using the latest development sources is possible via CVS. More information about how to use the SourceForge repository can be found on SourceForge.

### Warning

It should be noted that using the development sources can cause higher risks to the environment than the usual releases can do. Thus it is highly recommended to read the ocemp-devel mailing list on which actual development ist discussed.

## Integration in projects

The various components of OcempGUI can be used alone without the need to use another module of the package. If only a small event management system is needed, only the `ocempgui.events` module can be imported. If an event management exists and widgets are needed, only the `ocempgui.widgets` module needs to be imported and so on.

### Modules

The following OcempGUI modules are currently available:

`ocempgui.access`

  Provides various accessibility tools and interfaces for python, so that people with disabilities can easily use and access python applications. Generic interfaces for objects are available, which enable them to provide information for access-related technologies like braille keyboards or speech synthesizers. The `ocempgui.widgets` widget classes will integrate the interfaces of this module in future versions.

`ocempgui.draw`

  Provides various drawing primitives, on which the `ocempgui.widgets` module relies. Usually the methods of this module provide simplified wrappers for the pygame drawing functions as well as some more complex drawing object types.

`ocempgui.events`

  A small and fast event management system. It comes with an `EventManager` class, which takes care of distributing events to connected objects through signal queues. The event management system can deal with any type of data, which you want to use as event.

`ocempgui.object`

  Abstract object definitions, that allow you to rapidly create own classes, which are event capable through signal slots. Function or method callbacks can be connected to or disconnected from the signals, the object listens to. The `BaseObject` class is ready to be used with the `ocempgui.events` module.

`ocempgui.widgets`

  Various GUI elements for the creation and integration of interactive user interfaces. This module contains most commonly used user interface elements as well as abstract core definitions and interfaces to rapidly create own user interface elements. It also provides an own rendering class, which allows you to instantly create your pygame application without the need of taking care about an event and update loop.

## Implementing accessibility

### Accessibility for third-party applications

The `ocempgui.access` module provides a wrapper around the ATK accessibility library and several classes to ease the development of accessible applications. To serve different ability ranges, objects can be aware, the ATK developers use an C interface system, that has to be implemented for each toolkit. OcempGUI implements those interfaces using the `AtkObject` only and flags, that will enable or disable certain interfaces within that instance.

To use accessibility features in your code, you have to import the module using:

    import
            ocempgui.access

If you plan to integrate ATK support for third-parts accessibility solutions in your code, you should import the papi module in your code so you can use the ATK wrapper system.

    import ocempgui.access.papi

#### Making python objects accessible

To make python objects accessible and usable by accessibility-aware applications and hardware they should implement `IAccessible` interface class. It provides a single method interface, `get_accessible()`, which has to return an `AtkObject` object for the specific python instances.

    class A11yObject (IAccessible):
        def __init__ (self):
            IAccessible.__init__ (self)
            ...
        def get_accessible (self):
            obj = AtkObject (...)
            ...
            return obj

Dependant on the capabilities of the python object and the information it provides, it has to set up several attributes and/or implement various interfaces of the `AtkObject`, which will be returned.

TODO: provide more details

You can find the following example as a python script under `examples/a11y_test.py`.

    # papi test example.
    import ocempgui.access.papi as papi
    import atexit

    # Main object - somewhat similar to the GailTopLevel object.
    application = papi.AtkObject ()
    application.name = "Application object"
    application.description = "Application description"
    application.role = papi.ATK_ROLE_APPLICATION
    application.parent = None

    def get_application ():
        global application
        return application

    # Register the interfaces and initialize the atk-bridge.
    papi.set_atk_root (get_application)
    atexit.register (papi.shutdown)
    papi.init ()

    class SimpleA11y (papi.AtkObject):
        def __init__ (self):
            ifaces = papi.ATK_IFACE_COMPONENT | papi.ATK_IFACE_ACTION
            papi.AtkObject.__init__ (self, ifaces)

            # Implement some interfaces of ATK_IFACE_ACTION and
            # ATK_IFACE_COMPONENT.
            self.action_get_n_actions = self.__get_n_actions
            self.action_get_description = self.__get_description
            self.action_get_name = self.__get_name
            self.component_get_extents = self.__get_pos
            self.ref_state_set = self.__ref_state_set

        def __get_pos (self, coords):
            return 10, 10, 99, 99

        def __ref_state_set (self):
            return papi.AtkStateSet ()

        def __get_n_actions (self):
            return 1

        def __get_description (self, i):
            return "Example action."

        def __get_name (self, i):
            return "Example action name"

    # Window dummy as child of the toplevel application object.
    window = SimpleA11y ()

    # Retrieve the state set, so we can set it active.
    set = window.ref_state_set ()
    set.add_state (papi.ATK_STATE_ACTIVE)

    # Set some necessary information for accessibility applications.
    window.role  = papi.ATK_ROLE_WINDOW
    window.name = "Window A11y Object"
    window.description = "Window Description"

    # Link it with the application object
    window.parent = application

    # Signal testing - window:create will cause accessibility applications
    # to note, that a new window was created for the application.
    window.emit ("window:create")

    print "Keeping myself alive. Press CTRL-C to exit the application."
    while True:
        # Iterate the main processing loop of the ATK wrapper internals,
        # so that external applications can interact with the objects.
        papi.iterate ()

Example 1. ocempgui.access.papi test example

### Keyboard navigation - IIndexable

### Unhide the screen - the Magnifier

The `Magnifier` class of the `ocempgui.access` module is a screen magnification tool for pygame screens. It allows users to zoom portions of the current pygame screen, which are determined by the mouse cursor position. It allows different magnification factors and a variable sizing of the area to zoom.

The `Magnifier` can be integrated easily into any pygame mainloop and adjusted with minimal effort. To create a new instance of it, you simply can invoke its constructor with no arguments.

    magnifier = Magnifier ()

Alternatively you can also pass the initial area size to magnify and the zoom factor.

    # Use a magnification area of 100, 100 and a factor of 3.
    magnifier = Magnifier (100, 100, 3)

The zoom factor can be adjusted using the factor attribute and `set_factor()` method.

    magnifier.factor = 5.2
    magnifier.set_factor (0.5)

### Note

Values smaller than 1 will zoom out the affected area.

The size of the area around the mouse cursor, which should be magnified, can be adjusted using the size attribute and `set_size()` method.

    magnifier.size = 50, 50
    magnifier.set_size (40, 70)

The resulting magnification area will be the size multiplicated with the set factor and be centered at the current mouse position.

Integrating the `Magnifier` in a pygame application is done by just adding one or two lines of code. The most important line is to notify it about the available pygame events.

    while True:
        events = pygame.event.get ()
        magnifier.notify (*events)
        ...

This will enable it to react and refresh the magnified area and its position correctly upon the occurance of `pygame.MOUSEMOTION` events. Any other event will cause it to update its area only.

### Note

The update is done only once per `notify()` invocation. If multiple `pygame.MOUSEMOTION` events are in the passed list, only the last on will be used for repositioning.

If the pygame display is manipulated directly and thus needs to contain its original surface information (without the magnified area), the `restore()` method should be invoked before the manipulation occurs.

    while True:
        events = pygame.event.get ()

        magnifier.restore ()

        # Display manipulation
        ....

        magnifier.notify (*events)
        ...

This ensures that the original display contents are restored (the `Magnifier` will be suspended) before any manipulation takes place. Afterwards the `Magnifier` will be enabled again by passing the current events to it.

The `Magnifier` allows you to setup your own zoom function for best results when zooming parts of your application screen. The zoom_func attribute and `set_zoom_func()` method allow you to provide an own zoom function, which has to return the zoomed surface. It receives additional arguments, which are explained in detail in the inline documentation of the `Magnifier` class.

Implementing the `Magnifier`'s default zoom function could be achieved using the following code.

    def own_zoom_func (screen, mousepos, resultsize, size, factor):
        offset = mousepos[0] - size[0] / 2, mousepos[1] - size[1] / 2
        # Create zoomable surface.
        surface = pygame.Surface ((size[0], size[1]))
        surface.blit (screen, (0, 0), (offset[0], offset[1], size[0], size[1]))
        # Zoom and blit.
        return pygame.transform.scale (surface, (resultsize[0], resultsize[1]))

    # Assign the new zoom function.
    magnifier.zoom_func = own_zoom_func

## 2D drawing

The `ocempgui.draw` module contains several wrapper functions around various pygame drawing functions, which are used by the `ocempgui.widgets` module. It is divided in several submodules, of which each one contains various related functions such as creating rectangle surfaces, drawing strings or loading images. Although not any function defined within the `ocempgui.draw` module simplifies the usage of the pygame drawing functions, they can reduce the amount of code to write and several of them enable you to simplify specific operations.

To use the drawing routines in your own code, you can simply import the module using:

    import ocempgui.draw

### Geometric objects

The `ocempgui.draw.Draw` submodule contains several functions for geometric objects. Although most of them are only wrappers around the respective pygame functions, some of them can be used to create more complex geometric objects. The following list gives an overview about the functions defined within this submodule.

`draw_line (surface, color, a, b, width=1)`

  Draws a line with the given `width` from `a` to `b` on the passed `surface`. This function simply wraps the `pygame.draw.line()` function.

  You can find the following example as a python script under `examples/draw_line.py`.

      # Draw.draw_line () usage example.
      import pygame, pygame.locals
      from ocempgui.draw import Draw

      # Initialize the drawing window.
      pygame.init ()
      screen = pygame.display.set_mode ((200, 200))
      screen.fill ((250, 250, 250))
      pygame.display.set_caption ('Draw.draw_line ()')

      # Draw horizontal lines in different colors and sizes.
      for i in range (10):
          val = i * 10
          Draw.draw_line (screen, (0 + val, 50 + val, 40 + 2 * val),
                          (5, val), (195, val), i)

      # Draw vertical lines in different colors and sizes.
      for i in range (10):
          val = i * 8
          Draw.draw_line (screen, (0 + 2 * val, 30 + val, 35 + 2 * val),
                          (5 + i * 10, 100), (5 + i * 10, 195), i)

      # Draw a cross.
      Draw.draw_line (screen, (0, 0, 0), (120, 100), (195, 195), 3)
      Draw.draw_line (screen, (0, 0, 0), (195, 100), (120, 195), 3)

      # Show anything.
      pygame.display.flip ()

      # Wait for input.
      while not pygame.event.get ([pygame.locals.QUIT]):
          pass

  Example 2. Draw.draw_line ()

`draw_rect (width, height,color=None)`

  Creates a rectangle surface with a size of `width` and `height`, which can be manipulated and blitted on other surfaces. This function simply wraps the `pygame.Surface` function and calls `Surface.fill()` on demand.

  You can find the following example as a python script under `examples/draw_rect.py`.

      # Draw.draw_rect () usage example.
      import random
      import pygame, pygame.locals
      from ocempgui.draw import Draw

      # Initialize the drawing window.
      pygame.init ()
      screen = pygame.display.set_mode ((200, 200))
      screen.fill ((250, 250, 250))
      pygame.display.set_caption ('Draw.draw_rect ()')

      # Draw rectangles with various colors.
      rect = Draw.draw_rect (55, 40, (255, 0, 0))
      screen.blit (rect, (5, 5))

      rect = Draw.draw_rect (55, 40, (0, 255, 0))
      screen.blit (rect, (65, 5))

      rect = Draw.draw_rect (55, 40, (0, 0, 255))
      screen.blit (rect, (125, 5))

      # Draw encapsulated rectangles.
      for i in range (30):
          val = i + 3
          rnd = (random.randint (0, 5), random.randint (0, 5), random.randint (0, 5))
          color = (rnd[0] * i + 100,  rnd[1] * i + 100, rnd[2] * i + 100)
          rect = Draw.draw_rect (100 - 2 * val, 100 - 2 * val, color)
          screen.blit (rect, (5 + val, 50 + val))

      # Show anything.
      pygame.display.flip ()

      # Wait for input.
      while not pygame.event.get ([pygame.locals.QUIT]):
          pass

  Example 3. Draw.draw_rect ()

`draw_triangle (surface, color, a, b, c, width=0)`

  Draws a triangle using the vertices `a`, `b` and `c` on the passed `surface`. This function simply wraps the `pygame.draw.polygon()` function.

  You can find the following example as a python script under `examples/draw_triangle.py`.

      # Draw.draw_triangle () usage example.
      import pygame, pygame.locals
      from ocempgui.draw import Draw

      # Initialize the drawing window.
      pygame.init ()
      screen = pygame.display.set_mode ((200, 200))
      screen.fill ((250, 250, 250))
      pygame.display.set_caption ('Draw.draw_triangle ()')

      # Draw three triangles.
      Draw.draw_triangle (screen, (255, 0, 0), (20, 5), (5, 30), (35, 30), 0)
      Draw.draw_triangle (screen, (0, 255, 0), (25, 5), (40, 30), (55, 5), 0)
      Draw.draw_triangle (screen, (0, 0, 255), (60, 5), (45, 30), (75, 30), 0)

      # Draw a 'tunnel effect' of triangles.
      for i in range (30):
           val = i + 3
           color = (val * 4, val * 7, val * 5)
           Draw.draw_triangle (screen, color, (5 + 2 * val, 50 + val),
                               (195 - 2 * val, 50 + val), (100, 195 - 2 * val), 1)

      # Show anything.
      pygame.display.flip ()

      # Wait for input.
      while not pygame.event.get ([pygame.locals.QUIT]):
          pass

  Example 4. Draw.draw_triangle ()

### Image manipulation

The `ocempgui.draw.Image` submodule contains image related functions, such as loading or saving image data.

`load_image (filename, alpha=False, colorkey=None)`

  Loads an image from the specified `filename` and automatically converts it to the current display pixel format. If `alpha` is set to True, the method will try enable alpha transparency by using the `pygame.Surface.convert_alpha()` method. If the `colorkey` argument is set to a color value, the method tries to add color based transparency using the `pygame.Surface.set_colorkey()` method. This function is just a wrapper around `pygame.image.load()` and additionally calls `Surface.convert()`.

  You can find the following example as a python script under `examples/load_image.py`.

      # Image.load_image () usage example.
      import pygame, pygame.locals
      from ocempgui.draw import Image

      # Initialize the drawing window.
      pygame.init ()
      screen = pygame.display.set_mode ((120, 100))
      screen.fill ((250, 250, 250))
      pygame.display.set_caption ('Image.load_image ()')

      # Load an image and blit it on the screen.
      image = Image.load_image ("./image.png")
      screen.blit (image, (10, 10))

      # Show anything.
      pygame.display.flip ()

      # Wait for input.
      while not pygame.event.get ([pygame.locals.QUIT]):
          pass

  Example 5. Image.load_image ()

### Text rendering

The `ocempgui.draw.String` submodule contains functions, which allow the creation and manipulation of fonts and string surfaces. It includes a simple font caching system, which provides a fast availability of fonts, which were created earlier. Besides this feature, the string surface related functions are mostly wrappers around the respective pygame functions.

`create_font (fontfile, size, style)`

  Creates and returns a `pygame.Font` object from the given `fontfile` using the passed `size` and `style`. The font will be cached internally, so that a second invocation using the same `fontfile` and `size` will return the cached font.

  ### Note

  If you manipulate the returned `pygame.Font` directly, the manipulation will be applied to the cached font, too. To circumvent this behaviour, create a copy of the return value using the `pygame.Font.copy()` method and manipulate the copy.

  You can find the following example as a python script under `examples/create_font.py`.

      # String.create_font () usage example.
      import pygame
      from ocempgui.draw import String

      def check (font, name):
          bold = "not bold"
          if font.get_bold ():
              bold = "bold"
          print "%s at %s is %s" % (name, font, bold)

      # Initialize the pygame engine.
      pygame.init ()

      # Create a font from the ttf located in the current directory.
      font = String.create_font ("tuffy.ttf", 14)
      check (font, "font")

      # Now create a second font and manipulate it.
      # NOTE: Due to the caching we are using the same font object as above!
      font_mod = String.create_font ("tuffy.ttf", 14)
      font_mod.set_bold (True)

      # Output the bold state of both fonts.
      check (font, "font")
      check (font_mod, "font_mod")

  Example 6. String.create_font ()

`create_system_font (fontname, size, style)`

  Creates and returns a `pygame.Font` object from the given system font with the specified `fontname` and the given `size` and `style`. Like the `create_font()` function, the font will be cached internally, so that a second invocation with the same parameters will return the cached font.

  ### Note

  If you manipulate the returned `pygame.Font` directly, the manipulation will be applied to the cached font, too. To circumvent this behaviour, create a copy of the return value using the `pygame.Font.copy()` method and manipulate the copy.

  The `pygame.SysFont` documentation also notes this:

  | This will always return a valid Font object, and will fallback on the builtin pygame font if the given font is not found. |
  | --Pygame documentation

  You can find the following example as a python script under `examples/create_system_font.py`.

      # String.create_system_font () usage example.
      import pygame
      from ocempgui.draw import String

      # Initialize the pygame engine.
      pygame.init ()

      # Create some fonts.
      fonts = {}
      names = ( "Arial", "Helvetica", "Sans", "Serif", "Times" )
      for name in names:
          fonts[name] = String.create_system_font (name, 14)

      # Output the fonts as well as their object address.
      for name in fonts:
          print "Loaded: %s at %s" % (name, fonts[name])

  Example 7. String.create_system_font ()

`draw_string (text, font, size, antialias, color, style)`

  Creates a transparent surface displaying the `text` in the given `color` with the specified `style` applied. If `antialias` evaluates to True, the text will be rendered using antialiasing (if possible).

  ### Note

  The function first tries to resolve `font` as font file. If that fails, it looks for a system font name, which matches the `font` name and returns a Font object based on those information (or the fallback font of pygame, see also `create_system_font (fontname, size, style)` .

  You can find the following example as a python script under `examples/draw_string.py`.

      # String.draw_string () usage example.
      import pygame, pygame.locals
      from ocempgui.draw import String

      # Initialize the drawing window.
      pygame.init ()
      screen = pygame.display.set_mode ((400, 100))
      screen.fill ((250, 250, 250))
      pygame.display.set_caption ('String.draw_string ()')

      # Create a text using the ttf located in the current directory.
      text = String.draw_string ("This is tuffy.ttf", "tuffy.ttf", 16, 1, (0, 0, 0))
      screen.blit (text, (5, 5))

      # Create a text using the 'Times' system font
      text = String.draw_string ("This is Times", "Times", 16, 1, (255, 0, 0))
      screen.blit (text, (5, 35))

      # Create a text using the fallback python font by specifying a wrong
      # font name (hopefully ;-).
      text = String.draw_string ("This is the fallback", "invalid_font_name_here",
                                 16, 1, (0, 0, 255))
      screen.blit (text, (5, 60))

      # Now the same again without antialiasing.
      text = String.draw_string ("This is tuffy.ttf (no aa)", "tuffy.ttf",
                                 16, 0, (0, 0, 0))
      screen.blit (text, (200, 5))

      text = String.draw_string ("This is Times (no aa)", "Times",
                                 16, 0, (255, 0, 0))
      screen.blit (text, (200, 35))

      text = String.draw_string ("This is the fallback (no aa)",
                                 "invalid_font_name_here", 16, 1, (0, 0, 255))
      screen.blit (text, (200, 60))

      # Show anything.
      pygame.display.flip ()

      # Wait for input.
      while not pygame.event.get ([pygame.locals.QUIT]):
          pass

  Example 8. String.draw_string ()

`draw_string_with_bg (text, font, size, antialias, color, bgcolor, style)`

  This function is identical to the `draw_string (text, font, size, antialias, color, style)` function, except that it provides a background color via the `bgcolor` parameter.

  You can find the following example as a python script under `examples/draw_string_with_bg.py`.

      # String.draw_string_with_bg () usage example.
      import pygame, pygame.locals
      from ocempgui.draw import String

      # Initialize the drawing window.
      pygame.init ()
      screen = pygame.display.set_mode ((100, 100))
      screen.fill ((250, 250, 250))
      pygame.display.set_caption ('String.draw_string_with_bg ()')

      # Create texts using the 'Times' system font and different background
      # colors.
      text = String.draw_string_with_bg ("This is Times", "Times", 16, 1, (0, 0, 0),
                                         (200, 200, 200))
      screen.blit (text, (5, 5))

      text = String.draw_string_with_bg ("This is Times", "Times", 16, 1, (0, 0, 0),
                                         (0, 200, 0))
      screen.blit (text, (5, 60))

      # Show anything.
      pygame.display.flip ()

      # Wait for input.
      while not pygame.event.get ([pygame.locals.QUIT]):
          pass

  Example 9. String.draw_string_with_bg ()

### Complex objects

The `ocempgui.draw.Complex` module contains more advanced drawing objects, that implement interesting features for 2D graphics.

The `FaderSurface` class enhances the `pygame.Surface` class by some additional attributes and methods to support fade-in/fade-out operations. You can adjust them to fit its behaviour to your needs, such as setting the current transparency value using the alpha attribute

    surface.alpha = 0 # Make it completely transparent

or adjusting the step range for in- or decrements upon each update.

    surface.step = 5

You can find the following example as a python script under `examples/fader_surface.py`.

    # Complex.FaderSurface usage example.
    import pygame, pygame.locals
    from ocempgui.draw import Complex, Image

    # Initialize the drawing window.
    pygame.init ()
    screen = pygame.display.set_mode ((120, 100))
    screen.fill ((180, 180, 180))
    pygame.display.set_caption ('Complex.FaderSurface')

    # Create a surface we can use to display.
    image = Image.load_image ("./image.png")
    r = image.get_rect ()

    # Create a new FaderSurface with the same dimensions and an initial
    # transparency of 1.
    surface = Complex.FaderSurface (r.width, r.height, 1)

    # Blit the original on the FaderSurface.
    surface.blit (image, (0, 0))

    # The default step value is -1, but we want to fade the image in.
    surface.step = 1

    # Loop until the FaderSurface reached the maximum or minimum alpha
    # transparency value.
    while surface.update ():

        # Clean up and blit the surface..
        screen.fill ((180, 180, 180))
        screen.blit (surface, (10, 10))
        pygame.display.flip ()

        # Check the bounds. We have to check the maximum values - 1, because
        # 255 and 0 cause the surface to return False and we would exit the
        # loop.
        if surface.alpha == 254 or surface.alpha == 1:
            surface.step = -surface.step

        pygame.time.delay (50 / 4)

        # Wait for input.
        if pygame.event.get ([pygame.locals.QUIT]):
            break

Example 10. FaderSurface example

## Tracking object states - the observer pattern

OcempGUI provides a minimalistic observer pattern implementation in the `ocempgui.events` module, which enables objects to track changes ('observe') from others. Two classes, the `Subject` and `IObserver`, are used for this.

An object, which should expose changes is usually called a subject to which other objects, the observers, subscribe for notification about those changes. To create a subject, the class just needs to inherit from the `Subject` class, which provides a minimum set of methods and attributes to become observable.

    class MyObject (Subject):
        def __init__ (self):
            Subject.__init__ (self, "UniqueSubjectName")
        ...

The constructor of the `Subject` receives a string argument, the name, which identifies the object instance for possible observers.

The object now features all attributes and methods to register observers and to notify them about state changes. State changes however have to be emitted manually, so that the object should invoke its `notify()` method, whenever this is necessary.

    class MyObject (Subject):
        def __init__ (self):
            Subject.__init__ (self, "UniqueSubjectName")
            self._value = None

        def set_value (self, value):
            # Preserve old value.
            oldval = self._value

            # Set new value.
            self._value = value

            # Notify observers
            self.notify ('value', old, value)
        ...

Whenever `set_value()` is invoked now, any registered observer will be notified about

- The object, that changed its state (UniqueSubjectName).

- The name of the object part that changed (here the attribute value).

- The old and new value of the object part that changed.

An object that shall act as an observer should inherit from the `IObserver` class and implement its `update()` method, which will receive the state change notification from the `Subject`. The signature of the method looks like the following:

    class ObserverObject (IObserver):
        ...
        def update (self, subject, prop, oldval, newval):
            ...

### Note

Your classes do not need to explicitly inherit from `IObserver`, but have to implement the `update()` method with its correct signature.

The `subject` argument is the unique name of the `Subject` that just changed. `prop` identifies the detail that changed and `oldval` and `newval` contain the old and new value of the detail.

The following example is a complete example based on the excerpts from above. You can find it as python script under `examples/observer.py`

    # Subject/Observer usage example.
    from ocempgui.events import Subject, IObserver

    # The subject that should notify observers about state changes.
    class MyObject (Subject):
        def __init__ (self):
            Subject.__init__ (self, "MyObject")
            self._x = "Simple Attribute"
            self._y = 1234567890
            self._z = None

        def get_x (self):
            return self._x

        def set_x (self, value):
            # Preserve old value.
            old = self._x
            self._x = value
            # Notify about change.
            self.notify ("x", old, value)

        def get_y (self):
            return self._y

        def set_y (self, value):
            # Preserve old value.
            old = self._y
            self._y = value
            # Notify about change.
            self.notify ("y", old, value)

        def get_z (self):
            return self._z

        def set_z (self, value):
            # Preserve old value.
            old = self._z
            self._z = value
            # Notify about change.
            self.notify ("z", old, value)

        x = property (get_x, set_x)
        y = property (get_y, set_y)
        z = property (get_z, set_z)

    class OwnObserver (IObserver):
        def __init__ (self):
            pass

        def update (self, subject, prop, oldval, newval):
            if subject == "MyObject": # A MyObject instance, check details.
                if prop == "x":
                    # Its x value changed.
                    print "The x value of a MyObject instance changed from " \
                          "%s to %s" % (str (oldval), str (newval))
                elif prop == "y":
                    # Its y value changed.
                    print "The y value of a MyObject instance changed from " \
                          "%s to %s" % (str (oldval), str (newval))
                else:
                    # Another value changed.
                    print "The %s value of a MyObject instance changed from" \
                          "%s to %s" % (str (prop), str (oldval), str (newval))

    class AnotherObserver (IObserver):
        def __init__ (self):
            pass

        def update (self, subject, prop, oldval, newval):
            print "Detail %s of %s changed from %s to %s" % (str (prop), subject,
                                                             str (oldval),
                                                             str (newval))

    subject = MyObject ()

    # Add tow observers doing
    observer1 = OwnObserver ()
    observer2 = AnotherObserver ()

    subject.add (observer1, observer2)

    subject.x = "FooBarBaz"
    subject.y = subject.x * 3
    subject.z = 100

Example 11. Observer example

## Building event driven systems

The `ocempgui.events` module provides a small and fast event management system. It is currently separated into three different classes, of which the most important is the `EventManager` class. Besides the `EventManager`, an `Event` class for sending event data and an `EventCallback` class for connecting functions or methods to signals are available.

To create an own event driven application system or to enhance an existing application, only a few guidelines have to be respected and only a minimal set of changes be made on existing code. You will need to

- enable objects to receive events,

- set up the event management system.

To understand, what you are doing and to know the pitfalls of the event management system, you first have to know, how it works. The next subsection will give you a short explanation of it.

### How the event management works

The event management system of OcempGUI uses a simple approach using signal slots. This means, that objects will register themselves only for specific event types, of which they want to be notified. Any other event will not be sent to them.This reduces the overhead of events the objects have to deal with (either by dropping or processing them) and improves the performance and scalability of the event management system (especially with many objects).

Figure 1. Event management

### Enabling objects to receive events

An object, which shall be event aware, should inherit from the `INotifyable` class and implement its `notify()` method, which will receive events distributed by the `EventManager`. The signature of the method looks like the following:

    class OwnObject (INotifyable):
        ...
        def notify (self, event):
            ...

### Note

Your classes do not need to explicitly inherit from `INotifyable`, but have to implement the `notify()` method with its correct signature.

The `event` argument of the method will be an `Event` object, which can be used to perform certain actions within the method body then:

    class OwnObject (INotifyable):
        ...
        def move (self, coords):
           # Moves the object to the desired coordinates (x, y).
           self.x = coords[0]
           self.y = coords[1]
           print "Moved to %d,%d" % (self.x, self.y)

        def notify (self, event):
            # Check the event signal and run a certain action with its data.
            if event.signal == "clicked":
               print "Something was clicked!"
            elif event.signal == "move":
               # Assuming that the event.data contains a coordinate tuple.
               self.move (event.data)

Example 12. Enabling an object to receive events

### Setting up the event management

Setting up the main event management is nearly as easy as enhancing the objects. To add objects to the `EventManager`, the `add_object()` method has to be invoked. It receives the object to add and a list of signal ids as arguments. The signal ids will cause the object to be registered in specific queues, to which events with matching signal ids then will be sent.

Objects can be removed from the `EventManager` using the `remove_object()` method. The method allows you to either remove the object from specific slots or from all slots, it is registered for, at once.

We use the `OwnObject` class of the previous example and will (un)register it for the signals "move" and "clicked".

    # Create an EventManager and OwnObject instance.
    manager = EventManager ()
    myobj = OwnObject ()

    # Add the object to the EventManager.
    manager.add_object (myobj, "move", "clicked")

    # Remove the object from the 'clicked' slot.
    manager.remove_object (myobj, "clicked")

    # Remove the object from _all_ slots it still listens on.
    manager.remove_object (myobj)

Example 13. Adding and removing an object to the `EventManager`

### Sending events

Now let us proceed to the most important: sending events. To send events to the objects of the `EventManager`, you can use the `emit()` method. It receives two arguments, which will become the signal and data of a `Event` object. The `Event` will be created by the `EventManager` and then sent to the matching objects. So all you have to do is to pass the `emit()` method the correct information for the event.

Both arguments the `emit()` receives, have no limitations of type, length or whatsoever. It is up to you to to send correct information through the event management system and to check for correct information on the object side.

    # Send events to the registered objects via the emit() method.
    manager.emit ("clicked", None)
    manager.emit ("move", (10, 10))

Example 14. Sending events through the `EventManager`

### Complete event management example

The following example is a complete example based on the excerpts from above. You can find it as python script under `examples/eventmanager.py`

    # EventManager usage example.
    from ocempgui.events import EventManager, INotifyable

    # Create a new event capable object. This can be acquired by adding a
    # 'notify ()' method to the object, which receives a single argument.
    class OwnObject (INotifyable):
        def __init__ (self):
            self.x = 0
            self.y = 0

        def move (self, coords):
           # Moves the object to the desired coordinates (x, y).
           self.x = coords[0]
           self.y = coords[1]
           print "Moved to %d,%d" % (self.x, self.y)

        def notify (self, event):
            # Check the event signal and run a certain action with its data.
            if event.signal == "clicked":
               print "Something was clicked!"
            elif event.signal == "move":
               # Assuming that the event.data contains a coordinate tuple.
               self.move (event.data)

    # Create an EventManager and OwnObject instance.
    manager = EventManager ()
    myobj = OwnObject ()

    # Add the object to the EventManager.
    manager.add_object (myobj, "move", "clicked")

    # Send events to the registered objects via the emit() method.
    manager.emit ("clicked", None)
    manager.emit ("move", (10, 10))

    # Remove the object from the 'clicked' slot.
    manager.remove_object (myobj, "clicked")

    # Send the 'clicked' event once more.
    manager.emit ("clicked", None)

    # Remove the object from _all_ slots it still listens on.
    manager.remove_object (myobj)

    # Send the 'move' event again.
    manager.emit ("move", (40, 40))

Example 15. Complete event management example

## Making objects event capable - the better way

The previous section gave you a rough overview about how to use the OcempGUI event system with your own objects. As you might have seen, using only the `notify()` method and lengthy if-else conditions might not always be the best idea. Also, overriding the `notify()` method whenever the functionality of an object should change is not the best, especially, if it should be runtime dependant.

You might consider using the `BaseObject` from the `ocempgui.object` module instead. It offers ready to use signal slots and methods to bind callbacks at runtime, improving its and your flexibility without big effort.

### How the `BaseObject` works

The `BaseObject` is event driven, which means, that it acts and reacts upon events it receives and that it can raise events. Hereby you have to distinguish between Signals and Events. Signals are certain identifiers, a `BaseObject` can listen to, while Events are a combination of a Signal and additional data.

What does that mean in practice? As you already know from the section called “Building event driven systems”, objects will register themselves at an event manager with a specific signal, they listen to. Events in turn carry a specific signal id and additional data. A `BaseObject` will register itself at an event manager with its signals. If events are passed to the event manager, it will distribute them to the object, if needed. The object in turn will react according to its programming instructions.

To allow your object to react according to the application needs on certain events easily, the `BaseObject` supports the connection of callbacks to signals you can define for it. A callback is a method or function, which should be invoked, when the object receives a certain event.

Figure 2. Signal handling of the `BaseObject` class

### Creating event capable objects

The first thing you should do is to let your existing object or the newly created one inherit from the `BaseObject` class. Afterwards you can unleash its full power by adding just a minimal set of code.

    from ocempgui.object import BaseObject

    class OwnObject (BaseObject):
        def __init__ (self):
            BaseObject.__init__ (self)

        ...

Example 16. Inheriting from the `BaseObject` class

That is not all of course. You also have to set up the signals the object has to listen to and create callbacks. Let us create a small ping-pong example, where two objects react upon a 'ping' and 'pong' signal.

The `BaseObject` has a _signals attribute, which basically is a dictionary with the signal ids it listens to as keys and list for the callbacks as values. To allow your object to listen to the 'ping' or 'pong' signal, you have to add those to this dictionary.

    from ocempgui.object import BaseObject

    class OwnObject (BaseObject):
        def __init__ (self):
            BaseObject.__init__ (self)
            self._signals["ping"] = []
            self._signals["pong"] = []
        ...

Example 17. Adding a signal to the object

### Note

The list as value is mandatory to allow callbacks to be connected to those signals. If you are going to supply other types as value, keep in mind, that it is unlikely that connecting or disconnecting callbacks will work as supposed.

Now we just need to make the `notify()` aware of those signal types and let it invoke the appropriate callbacks, which will be connected to those signals.

    class OwnObject (BaseObject):
        ...
        def notify (self, event):
            if event.signal == "ping":
                self.run_signal_handlers ("ping")
            elif event.signal == "pong":
                self.run_signal_handlers ("pong")

Example 18. Setting up the notify() method

As you see, the `run_signal_handlers()` takes care of invoking the connected callbacks. Now you have anything set up to allow the object to listen to specific events, to connect callbacks to it and let it invoke them, when it receives the specific signal.

To connect methods or functions as callbacks to a specific signal, the `connect_signal()` method of the `BaseObject` can be used. It allows additional data to be passed to the callback by specifiying the data right after the signal and callback. If the callbacks is not needed anymore, it can be disconnected using the `disconnect_signal()` method.

    class OwnObject (BaseObject):
        ...

    my_obj = OwnObject ()
    ev_callback1 = my_obj.connect_signal ("ping", ping_callback, data)
    ev_callback2 = my_obj.connect_signal ("pong", pong_callback, data1, data2)
    ...

    my_obj.disconnect_signal (ev_callback1)
    my_obj.disconnect_signal (ev_callback2)

Example 19. Connecting and disconnecting callbacks.

Now it just needs to be connected to an event manager. In contrast to the earlier section, you do not need to register any signal of your `BaseObject` inheritor manually. When you connect it to an event manager, it will automatically do that for you.

    class OwnObject (BaseObject):
        ...

    manager = EventManager
    my_obj = OwnObject ()

    # Any signal of the object will be registered automatically.
    my_obj.manager = manager

Example 20. Connecting the object to an event manager.

The last important thing to know about the `BaseObject` is its ability to emit events. If the object is connected to an event manager, you can let it send events through the manager with the object its `emit()` method. The syntax is the same as if you would emit events on the `EventManager` directly.

Now let us look at the example we just went through (the following one is slightly modified only). You can find the example as python script under `examples/baseobject.py`

    # BaseObject usage example.
    from ocempgui.object import BaseObject
    from ocempgui.events import EventManager

    # Callbacks, which should be invoked for the object.
    def ping_callback (obj, additional_data):
        print "The object is: %s" % obj.name
        print "Passed data is: %s" % additional_data

    def pong_callback ():
        print "Another callback with no arguments."

    # Object implementation, which can listen to specific events.
    class OwnObject (BaseObject):
        def __init__ (self, name):
            BaseObject.__init__ (self)
            self.name = name
            # The object should be able to listen to 'ping' and 'pong'
            # events.
            self._signals["ping"] = []
            self._signals["pong"] = []

        def notify (self, event):
            # This simple notify method will not be used in this
            # example. Instead, the signals are invoked directly.
            if event.signal == "ping":
                self.run_signal_handlers ("ping")
            elif event.signal == "pong":
                self.run_signal_handlers ("pong")

    manager = EventManager ()

    # Create an object and connect callbacks to its both events.
    my_obj = OwnObject ("First object")
    ev1 = my_obj.connect_signal ("ping", ping_callback, my_obj, "data")
    ev2 = my_obj.connect_signal ("pong", pong_callback)

    # Connect it to the event manager
    my_obj.manager = manager

    # Invoke the connected signals handlers for a specific event.
    manager.emit ("ping", None)
    manager.emit ("pong", None)

    # After disconnecting a callback, it will not be invoked anymore.
    my_obj.disconnect_signal (ev1)
    my_obj.disconnect_signal (ev2)
    manager.emit ("ping", None)
    manager.emit ("pong", None)

Example 21. Ping-Pong with a BaseObject

### Events on demand: the `ActionListener`

The `ocempgui.object` module includes another event capable object class, the `ActionListener`, which inherits from the `BaseObject` class, but allows you to create and delete signals and listening queues as you need them without the necessity to subclass.

The `ActionListener` creates the signal id and a callback queue, when you connect a callback to it and registers itself for this signal automatically at its event manager. This can be extremeley useful, if a more flexible event capable object type is needed, which does not need to do any sanity checks on the event data. Instead it will send the event data to the callback as well, which then can work with it.

Once more let us create a ping-ping example using the `ActionListener` class instead of a `BaseObject` now.

You can find the example as python script under `examples/actionlistener.py`

    # ActionListener usage example.
    import sys
    from ocempgui.events import EventManager
    from ocempgui.object import ActionListener

    count = 0

    def emit_pong (event, manager):
        print "emit_pong received: [%s] - emitting pong..." % event
        manager.emit ("pong", "pong_event")

    def emit_ping (event, manager):
        global count
        if count > 10:
            sys.exit ()
        count += 1
        print "emit_ping received: [%s] - emitting ping..." % event
        manager.emit ("ping", "ping_event")

    # Create an event manager and two ping-pong listeners.
    manager = EventManager ()

    listener1 = ActionListener ()
    listener1.connect_signal ("ping", emit_pong, manager)
    listener1.manager = manager

    listener2 = ActionListener ()
    listener2.connect_signal ("pong", emit_ping, manager)
    listener2.manager = manager

    # start ping-pong actions
    print "Starting Ping-Pong"
    manager.emit ("ping", "ping_event")

Example 22. Ping-Pong with the ActionListener

Looking at the first interesting line, line eight,

    def emit_pong (event, manager):
        print "emit_pong received: [%s] - emitting pong..." % event
        manager.emit ("pong", "pong_event")

you will notice, that the signature of the function slightly has changed. Instead of receiving the additional data of a callback connection, it gets the event data of the event here. As second object it receives an `EventManager` object, on which it emits a pong event with additional data then.

Line twelve and following does the same, but breaks, if it was invoked more than ten times.

The next lines of interest are line twenty-three to twenty-nine,

    listener1 = ActionListener ()
    listener1.connect_signal ("ping", emit_pong, manager)
    listener1.manager = manager

in which two `ActionLister` objects will be created and signal slots and callbacks for the 'ping' and 'pong' events will be set up. In line twenty-five and twenty-nine the objects will be registered at the event manager created earlier in the code.

### Note

Although this class is very mighty, you should not use it as base for own event capable classes. When the feature set and code amount of your own classes grow, it easily can happen, that you oversee events or that you do not understand which signals it should deal with anymore.

It is however a good and valuable class type to work as proxy or to delegate events to different functions or methods in a context sensitive manner.

## Creating GUI applications

### Getting started

The first thing an application using OcempGUI should do is to initialize the renderering system. The `Renderer` class from the `ocempgui.widgets` package contains all necessary parts to take care of this. It includes

- the event mangement

- a sprite based render engine

- methods to create the pygame window

The `Renderer` can be set up with only three lines of code.

    from ocempgui.widgets import *
    re = Renderer ()
    re.create_screen (200, 200) # Creates the pygame window

Example 23. Setting up the Renderer

### Hello World with OcempGUI

Now that the `Renderer` is set up, you can start to place widgets on the pygame window by adding them using the `Renderer.add_widget()` method. Let us do this by building a simple (and well-known) application with a `Button` widget on it, that displays 'Hello World'.

You can find the example as python script under `examples/hello_world.py`

    # Hello World example.
    from ocempgui.widgets import *

    # Initialize the drawing window.
    re = Renderer ()
    re.create_screen (100, 50)
    re.title = "Hello World"
    re.color = (250, 250, 250)

    button = Button ("Hello World")
    button.topleft = (10, 10)
    re.add_widget (button)

    # Start the main rendering loop.
    re.start ()

Example 24. Hello World with OcempGUI

The second line

    from ocempgui.widgets import*

is the usual directive to import anything from the `ocempgui.widgets` module you will need to build an application. It is also possible to use a fine grained selection of classes and submodules to import, but mostly the above code will serve well.

The fifth and sixth lines

    re = Renderer ()
    re.create_screen (100, 50)

create a new `Renderer` object, which takes care of updating the screen and the event management and create a pygame window with a 100x50 size.

The seventh and eight line

    re.title = "Hello World"
    re.color = (250, 250, 250)

set the the title caption of the pygame window and the background color (here as RGB value) for the window. Those are not necessary code, but at least the title will help window managers to display the pygame window correctly within their window lists, etc.

In line ten

    button = Button ("Hello World")

the `Button` widget is created. The constructor can receive an additional argument with the text, the `Button` should display.

The next line will place the `Button` at a specific position.

    button.topleft = (10, 10)

The topleft attribute always refers to the topleft corner of the widget and can be used to place widgets at the desired coordinates on the pygame window.

Line twelve

    re.add_widget (button)

adds the button to the Renderer, which will enable the button to be displayed, receive events and send events.

The last line will start the main processing loop of the `Renderer`.

    re.start ()

When the program reaches this line of code, the processing is passed to the `Renderer`, which will wait for events, draw and update the widgets and so on.

### Events and Signals

Every widget of OcempGUI inherits from the `ocempgui.object.BaseObject` class and its event handling makes heavy usage of the `BaseObject` features.

To cause a `Button` to print a message upon a mouse click, you would connect a message printing function to the click signal of the `Button`. In turn, if this callback is not needed anymore in the later program flow, you would disconnect the function from the `Button`'s signal.

This theoretical model is used in many different toolkits and OcempGUI stays with it. We will enhance our 'Hello world' example application from the previous chapter with a callback now, wich prints a message each time the `Button` is clicked.

You can find the example as python script under `examples/hello_world_signals.py`

    # Hello World example.
    from ocempgui.widgets import *
    from ocempgui.widgets.Constants import *

    def print_message  ():
        print "The button was clicked!"

    # Initialize the drawing window.
    re = Renderer ()
    re.create_screen (100, 50)
    re.title = "Hello World"
    re.color = (250, 250, 250)

    button = Button ("Hello World")
    button.topleft = (10, 10)
    button.connect_signal (SIG_CLICKED, print_message)
    re.add_widget (button)

    # Start the main rendering loop.
    re.start ()

Example 25. Hello World with callbacks

The first change you note is the new import directive in line three.

    from ocempgui.widgets.Constants import *

This will import the set of common constants used within the `ocempgui.widgets` module. The availabe signal identifiers used by the various widgets of OcempGUI area prefixed with SIG_.

Line five and six contain the function, which will be used as the callback for the button. It is indifferent, if the callback is a class or object method or a function. Both cases will work in the same way.

The next notably change was done in line 16

    button.connect_signal (SIG_CLICKED, print_message)

This tells the `Button` to invoke the `print_message` function each time it is clicked. You also could send additional data to the callback as you already know from the section called “Making objects event capable - the better way”. Anything written about the signal handling of the `BaseObject` class applies to the widgets, too.

## Widget overview

The following sections cover the possibilities and capabilities of the different widgets, the `ocempgui.widgets` module offers. The sections will not cover any method and attribute of the widgets in detail, but just the most important ones. It is strongly recommended, that you read through the doc strings of the widgets, too, to get a complete overview about them.

### General settings

The `ocempgui.widgets` module contains some globally accessed settings, that influence its complete behaviour. Those can be found in the `ocempgui.widgets.base` part and contain the `Style`, which is currently in use, the timer rate for double-clicks and a debugging flag. You can adjust those settings easily by simply binding them to new values.

Before you go ahead and change base.GlobalStyle, you should read the section called “Changing the widget appearance”.

The base.debug setting is for additional debugging output and should not be set to True usually (unless you are using a development version).

The last one, base.DoubleClickRate should be set using the `base.set_doubleclick_rate()` method only and denotes the maximum time to elaps between two click operations to identify them as a double-click.

## Common widget operations - the BaseWidget

The `BaseWidget` is the most basic class of all widgets and contains common attributes and methods, each widget of the `ocempui.widgets` module has to include. Every widget inherits from it, so that any description and explanation in this section also to the widgets, which are explained later on.

### Positioning and sizing

A widget can be set to a specific position on the main screen using the topleft attribute.

    widget.topleft = 10, 15

Using the above code, the topleft corner of the widget will bo positioned at the x-coordinate 10 and the y-coordinate 15 of the main screen, of which 0, 0 denotes the topleft corner.

### Note

This will not work as supposed using widgets, that are bound to a `Container` or `Bin` widget, which will be explained in one of the following sections.

If you read the current topleft value of a widget, keep in mind, that it will return a tuple containing the both, x and y, coordinates.

Every widget supports a minimum size, that will be respected by the default drawing methods.

    widget.minsize = 80, 20

The minimum size is the guaranteed width and height, the widget should occupy on the screen. It can grow beyond that minimum size, if this is needed to display all of its contents according to its drawing method, but will never be smaller than this value.

The currently used width and height, which can differ from its minsize can be retrieved using the width and height attributes or as tuple using the size.

    if (widget.width == widget.minsize[0]) and (widget.height == widget.minsize[1]):
        print "Widget does not exceed its minimum size."

The counterpart to the minsize attribute is maxsize. A widget will never grow beyond the values of it, if set.

### Note

The `BaseWidget` class exports all `pygame.Rect` attributes, so you are not limited to the topleft only, but can also use the `pygame.Rect` attributes you are used to. See the pygame.Rect documentation for more details.

### Keyboard support

To allow an easy and logical keyboard navigation, widgets have an index attribute, which influences the navigation order using the keyboard.

    widget.index = 3

A lower index will cause the widget to receive the input focus earlier. It is highly recommended, that you set this value in your own code to provide the user a better keyboard accessibility.

The input focus mentioned above denotes a state of the widget, in which the user can interact with it using the keyboard only. A `Button` widget will react upon pressing the space bar with a click while an `Entry` widget will let the user type text. You can set the input focus of a widget manually with the focus attribute.

    widget.focus = True

This however will not work with any widget (e.g. layout containers such as the `Table`). Dependant on the widget the set_focus() method of it will return either True or False, which indicates, that the input focus could be sucessfully set for that widget or not.

    frame = VFrame ()
    focusok = frame.set_focus (True)
    if not focusok:
        print "Focus could not be set."

### Other features

Widgets can be disabled from user interaction and receiving events, if you set their sensitive attribute to False.

    widget.sensitive = False

They will be set in a different state then to indicate, that the user cannot interact with them anymore. Of course you can reset the sensitivity at any time.

The renderering system of the `ocempgui.widgets` module can use different layers, on which widgets are drawn. This is especially useful and often necessary to place widgets above others (e.g. to place a `Window` widget above another one).

    widget.depth = 3

The above code causes the widget to be drawn above all widgets, which have a depth value smaller than three, but under any widget, that has a higher depth. You can find an example demonstrating this in the section called “Window”. The layer feature is described in detail in the section called “The layer and indexing system”.

Widgets support transparency using the alpha color channel. To set it for a widget use the opacity attribute of it. The opacity attribute accepts values betwee 0 (fully transparent) and 255 (not transparent, default).

    widget.opacity = 100

To change the appearance of a single widget instance, the `create_style()` method and style attribute of a widget can be used. While `create_style()` will generate an instance specific style dictionary for the widget, style can be used to have quick access to it, once it is created.

    # Create an instance specific style dictionary for the widget and return a
    # reference to it.
    style = widget.create_style()
    ...

    # Access the created style dictionary of the widget.
    widget.style[...] = ...

To avoid unnecessary overhead, the style attribute of a widget will not be set to anything by default. It will be filled with something useful on th first invocation of `create_style()`.

Changing instance specific styles is explained in detail in the section called “Changing the appearance of single instances”.

## Labels

Labels are non-interactive decorative user interface elements, which provide certain information to the user.

### Label

The `Label` class can display a short amount of text and allows you to control interaction with other widgets using keyboard mnemonics.

To create a `Label`, you typically will use

    my_label = Label (text)

The sole argument is the text to display.

To set the text after creation, use the text attribute or `set_text()` method.

    label.text = "New Text"
    label.set_text ("New Text")

It is possible to have multiline text by setting the multiline attribute to True:

    label.multiline = True
    label.set_multiline (True)

Multiple text lines can be created by the newline character ('\n')

Labels support keyboard accelerators, so called mnemonics, which can activate other widgets. The '#' will cause the directly following to work as mnemonic character. If you want to cause the `Label` to display a normal '#', use '##' in the text.

    label.text = '#Mnemonic'
    label.set_text ('A simple hash: ##')

If a mnemonic is set up, you usually have to set the widget, which should be activated by the mnemonic as well.

    label.widget = another_widget

Below you will find an example to illustrate most of the abilities of the `Label` widget class. You do not need to care about other widgets like the `Frame` class for now as those are explained later on.

You can find the following example as a python script under `examples/label.py`.

    # Label examples.
    import os
    from ocempgui.widgets import *
    from ocempgui.widgets.Constants import *

    def _create_vframe (text):
        frame = VFrame (Label (text))
        frame.spacing = 5
        frame.align = ALIGN_LEFT
        return frame

    def create_label_view ():
        states = ("STATE_NORMAL", "STATE_ENTERED", "STATE_ACTIVE",
                  "STATE_INSENSITIVE")

        table = Table (2, 3)
        table.spacing = 5
        table.set_row_align (0, ALIGN_TOP)
        table.set_row_align (1, ALIGN_TOP)

        # Frame with the states.
        frm_states = _create_vframe ("States")
        for i, s in enumerate (states):
            lbl = Label (s)
            if STATE_TYPES[i] == STATE_INSENSITIVE:
                lbl.sensitive = False
            else:
                lbl.state = STATE_TYPES[i]
            frm_states.add_child (lbl)
        table.add_child (0, 0, frm_states)

        # Frame with different padding.
        frm_padding = _create_vframe ("Padding")
        for i in xrange (5):
            lbl = Label ("Padding: %dpx" % (i * 2))
            lbl.padding = i * 2
            frm_padding.add_child (lbl)
        table.add_child (0, 1, frm_padding)

        # Frame with mnemonic support.
        frm_mnemonics = _create_vframe ("Mnemonics")
        strings = ("#Simple Mnemonic", "A ## is displayed using '####'",
                   "M#ultiple M#nemonics #have no #effect")
        for s in strings:
            lbl = Label (s)
            frm_mnemonics.add_child (lbl)
        table.add_child (0, 2, frm_mnemonics)

        # Frame with multiline labels.
        frm_multiline = _create_vframe ("Multiline labels")
        frm_multiline.align = ALIGN_NONE
        strings = ("Single line", "First lines\nSecond line",
                   "First line\nSecond line\nThird Line",
                   "Two lines with a\n#mnemonic")
        for s in strings:
            lbl = Label (s)
            lbl.multiline = True
            frm_multiline.add_child (lbl)
        table.add_child (1, 0, frm_multiline)
        return table

    if __name__ == "__main__":
        # Initialize the drawing window.
        re = Renderer ()
        re.create_screen (500, 350)
        re.title = "Label examples"
        re.color = (234, 228, 223)
        re.add_widget (create_label_view ())
        # Start the main rendering loop.
        re.start ()

Example 26. Label example

### ImageLabel

The `ImageLabel` is a decorative widget holding an image and not much functionality besides that. It does not support mnemonics nor text and is mainly used to display images in a GUI, whenever they should fit smoothly into the layout.

To create an `ImageLabel`, you have pass either the name of a file to load (including the full path to it) or a `pygame.Surface` object to display.

    imagelabel = ImageLabel ("path/to/an/image.png")
    imagelabel = ImageLabel (pygame_surface)

Of course the image can be changed at any time using the picture attribute or `set_picture()` method.

In contrast to the `Label` class, the `ImageLabel` supports different border styles to adjust its look and feel without the need to override its drawing methods.

    imagelabel.border = BORDER_NONE
    imagelabel.set_border (BORDER_NONE)

Below you will find an example to illustrate most of the abilities of the `ImageLabel` widget class. You do not need to care about other widgets like the `Frame` class for now as those are explained later on.

You can find the following example as a python script under `examples/imagelabel.py`.

    # ImageLabel examples.
    import os
    from ocempgui.draw import Image
    from ocempgui.widgets import *
    from ocempgui.widgets.Constants import *

    def _create_vframe (text):
        frame = VFrame (Label (text))
        frame.spacing = 5
        frame.align = ALIGN_LEFT
        return frame

    def create_imagelabel_view ():
        image = Image.load_image ("./image.png")
        table = Table (1, 3)
        table.spacing = 5
        table.set_row_align (0, ALIGN_TOP)

        # Frame with the states.
        frm_states = _create_vframe ("States")
        for i, s in enumerate (STATE_TYPES):
            lbl = ImageLabel (image)
            if s == STATE_INSENSITIVE:
                lbl.sensitive = False
            else:
                lbl.state = s
            frm_states.add_child (lbl)
        table.add_child (0, 0, frm_states)

        # Frame with different padding.
        frm_padding = _create_vframe ("Padding")
        for i in xrange (5):
            lbl = ImageLabel (image)
            lbl.border = BORDER_FLAT
            lbl.padding = i * 2
            frm_padding.add_child (lbl)
        table.add_child (0, 1, frm_padding)

        # Borders.
        frm_borders = _create_vframe ("Borders")
        for border in BORDER_TYPES:
            lbl = ImageLabel (image)
            lbl.border = border
            frm_borders.add_child (lbl)
        table.add_child (0, 2, frm_borders)
        return table

    if __name__ == "__main__":
        # Initialize the drawing window.
        re = Renderer ()
        re.create_screen (500, 350)
        re.title = "ImageLabel examples"
        re.color = (234, 228, 223)
        re.add_widget (create_imagelabel_view ())
        # Start the main rendering loop.
        re.start ()

Example 27. ImageLabel example

## Buttons

Buttons are interactive user interface elements, which usually react upon mouse events such as clicks or similar events.

### Button

You already learned about the `Button` widget in an earlier section, so let us look at some interesting details of it now.

The `Button` widget is a interactive widget, which reacts upon mouse input such as clicks. Basically it is a container (which will be explained detailled later on), which holds a `Label` widget to display its text.

To create a `Button`, you usually will type

    button = Button (text)

The usage of mnemonics for the Button is easy to achieve by simply supplying a mnemonic text as described in the section called “Label”. You can set the text directly through the text attribute or `set_text()` method.

    button.text = "#Mnemonic"
    button.set_text ("#Mnemonic")

It is not needed to explicitly set the widget attribute of the `Button` its `Label` as this already has been done on creation of the `Button`.

The `Button` supports different border styles to adjust its look and feel without the need to override its drawing methods.

    button.border = BORDER_NONE
    button.set_border (BORDER_NONE)

The `Button` widget has some default signals, it listens to. Those are

- SIG_MOUSEDOWN - Invoked, when a mouse button is pressed down on the Button.

- SIG_MOUSEUP - Invoked, when a mouse button is released on the Button.

- SIG_MOUSEMOVE - Invoked, when the mouse moves over the Button area.

- SIG_CLICKED - Invoked, when the left mouse button is pressed and released over the Button.

Below you will find an example to illustrate most of the abilities of the `Button` widget class. You do not need to care about other widgets like the `Frame` class for now as those are explained later on.

You can find the following example as a python script under `examples/button.py`.

    # Button examples.
    import os
    from ocempgui.widgets import *
    from ocempgui.widgets.Constants import *

    def _create_vframe (text):
        frame = VFrame (Label (text))
        frame.spacing = 5
        frame.align = ALIGN_LEFT
        return frame

    def create_button_view ():
        states = ("STATE_NORMAL", "STATE_ENTERED", "STATE_ACTIVE",
                  "STATE_INSENSITIVE")

        table = Table (2, 3)
        table.spacing = 5
        table.set_row_align (0, ALIGN_TOP)
        table.set_row_align (1, ALIGN_TOP)

        # Frame with the states.
        frm_states = _create_vframe ("States")
        for i, s in enumerate (states):
            btn = Button (s)
            if STATE_TYPES[i] == STATE_INSENSITIVE:
                btn.sensitive = False
            else:
                btn.state = STATE_TYPES[i]
            frm_states.add_child (btn)
        table.add_child (0, 0, frm_states)

        # Frame with different padding.
        frm_padding = _create_vframe ("Padding")
        for i in xrange (5):
            btn = Button ("Padding: %dpx" % (i * 2))
            btn.padding = i * 2
            frm_padding.add_child (btn)
        table.add_child (0, 1, frm_padding)

        # Mnemonics.
        frm_mnemonic = _create_vframe ("Mnemonics")
        btn = Button ("#Simple Mnemonic")
        btn2 = Button ("#Activate using <ALT><Underlined Key>")
        frm_mnemonic.add_child (btn, btn2)
        table.add_child (0, 2, frm_mnemonic)

        # Borders.
        frm_borders = _create_vframe ("Borders")
        btn_raised = Button ("Raised border")
        btn_sunken = Button ("Sunken border")
        btn_sunken.border = BORDER_SUNKEN
        btn_flat = Button ("Flat border")
        btn_flat.border = BORDER_FLAT
        btn_none = Button ("No border")
        btn_none.border = BORDER_NONE
        btn_etchedin = Button ("Etched in")
        btn_etchedin.border = BORDER_ETCHED_IN
        btn_etchedout = Button ("Etched out")
        btn_etchedout.border = BORDER_ETCHED_OUT
        frm_borders.add_child (btn_raised, btn_sunken, btn_flat, btn_none,
                               btn_etchedin, btn_etchedout)
        table.add_child (1, 0, frm_borders)

        # Multiline labeled buttons
        frm_multiline = _create_vframe ("Multiline labels")
        strings = ("Single lined Button", "Two lines on\na Button",
                   "Two lines with a\n#mnemonic")
        for s in strings:
            button = Button (s)
            button.child.multiline = True
            frm_multiline.add_child (button)
        table.add_child (1, 1, frm_multiline)

        # Empty buttons with different minimum sizes
        frm_empty = _create_vframe ("Empty Buttons")
        for i in xrange (5):
            button = Button ()
            button.minsize = (20 * i, 10 * i)
            frm_empty.add_child (button)
        table.add_child (1, 2, frm_empty)

        return table

    if __name__ == "__main__":
        # Initialize the drawing window.
        re = Renderer ()
        re.create_screen (550, 470)
        re.title = "Button examples"
        re.color = (234, 228, 223)
        re.add_widget (create_button_view ())
        # Start the main rendering loop.
        re.start ()

Example 28. Button example

### ImageButton

The `ImageButton` is basically a subclass of the `Button`, but enhances it by the ability to load and display image data. It supports any image data format, that can be handled by the underlying pygame library. Due to its inheritance, everything said about the `Button` widget applies to the `ImageButton` as well.

The creation of an `ImageButton` is slightly different to the `Button`. Instead of passing the text to display, you can pass either the name of a file to load (including the full path to it) or a `pygame.Surface` object to display, just like the `ImageLabel` class.

    button = ImageButton ("path/to/an/image.png")
    button = ImageButton (pygame_surface)

Of course it is possible to supply text through the text attribute, too, which then will be displayed right besides the image.

    button.text = "Additional text"

Below you will find an example to illustrate most of the abilities of the `ImageButton` widget class. You do not need to care about other widgets like the `Frame` class for now as those are explained later on.

You can find the following example as a python script under `examples/imagebutton.py`.

    # ImageButton examples.
    import pygame, os
    from ocempgui.draw import Image
    from ocempgui.widgets import *
    from ocempgui.widgets.Constants import *

    def _create_vframe (text):
        frame = VFrame (Label (text))
        frame.spacing = 5
        frame.align = ALIGN_LEFT
        return frame

    def create_button_view ():
        states = ("STATE_NORMAL", "STATE_ENTERED", "STATE_ACTIVE",
                  "STATE_INSENSITIVE")

        image = Image.load_image ("./image.png")
        table = Table (2, 2)
        table.spacing = 5
        table.set_row_align (0, ALIGN_TOP)
        table.set_row_align (1, ALIGN_TOP)

        # Frame with the states.
        frm_states = _create_vframe ("States")
        for i, s in enumerate (states):
            btn = ImageButton (image)
            if STATE_TYPES[i] == STATE_INSENSITIVE:
                btn.sensitive = False
            else:
                btn.state = STATE_TYPES[i]
            btn.text = s
            frm_states.add_child (btn)
        table.add_child (0, 0, frm_states)

        # Frame with different padding.
        frm_padding = _create_vframe ("Padding")
        for i in xrange (4):
            btn = ImageButton (image)
            btn.padding = i * 2
            frm_padding.add_child (btn)
        table.add_child (0, 1, frm_padding)

        # Mnemonics.
        frm_mnemonic = _create_vframe ("Mnemonics")
        btn = ImageButton (image)
        btn.text = "#Simple Mnemonic"
        btn2 = ImageButton (image)
        btn2.text = "#Activate using <ALT><Underlined Key>"
        frm_mnemonic.add_child (btn, btn2)
        table.add_child (1, 0, frm_mnemonic)

        # Multiline labeled ImageButton
        frm_multiline = _create_vframe ("Multiline label")
        button = ImageButton (image)
        button.text = "Multiple lines\nwith a #mnemonic"
        button.child.multiline = True
        frm_multiline.add_child (button)
        table.add_child (1, 1, frm_multiline)

        return table

    if __name__ == "__main__":
        # Initialize the drawing window.
        re = Renderer ()
        re.create_screen (570, 400)
        re.title = "ImageButton examples"
        re.color = (234, 228, 223)
        re.add_widget (create_button_view ())
        # Start the main rendering loop.
        re.start ()

Example 29. ImageButton example

### ToggleButton

Inherited from the `Button` the `ToggleButton` widget does not differ from it except that it is always in one state, either active or inactive, which are alternated by a click. By default it is displayed in a depressed state on a click and pops up after clicking it again.

To create a `ToggleButton`, you can do the same as with the `Button` class.

    button = ToggleButton (text)

You can retrieve the current state as boolean value of the `ToggleButton` through its active attribute and set its state programmatically via this attribute or the `set_active()` method.

    if button.active:
        print "The ToggleButton is currently active!"
    button.set_active (False)

This also applies to the `CheckButton` and `RadioButton` classes in the next sections.

To track changes of this state, the `ToggleButton` supplies a SIG_TOGGLED signal, which will be raised, if the state is changed via a mouse input or the accelerator action of a `Label`.

    def state_changed (togglebutton):
        state = "active"
        if not togglebutton.active:
           state = "inactive"
        out = "The state of the ToggleButton has been set to %s" % state

    button = ToggleButton ("A ToggleButton")
    button.connect_signal (SIG_TOGGLED, state_changed, button)

The signal will not be raised, if the state is set programmatically.

Below you will find an example to illustrate most of the abilities of the `ToggleButton` widget class. You do not need to care about other widgets like the `Frame` class for now as those are explained later on.

You can find the following example as a python script under `examples/togglebutton.py`.

    # ToggleButton examples.
    import os
    from ocempgui.widgets import *
    from ocempgui.widgets.Constants import *

    def _create_vframe (text):
        frame = VFrame (Label (text))
        frame.spacing = 5
        frame.align = ALIGN_LEFT
        return frame

    def create_button_view ():
        states = ("STATE_NORMAL", "STATE_ENTERED", "STATE_ACTIVE",
                  "STATE_INSENSITIVE")

        table = Table (2, 3)
        table.spacing = 5
        table.set_row_align (0, ALIGN_TOP)
        table.set_row_align (1, ALIGN_TOP)

        # Frame with the states.
        frm_states = _create_vframe ("States")
        for i, s in enumerate (states):
            btn = ToggleButton (s)
            if STATE_TYPES[i] == STATE_INSENSITIVE:
                btn.sensitive = False
            else:
                btn.state = STATE_TYPES[i]
            frm_states.add_child (btn)
        table.add_child (0, 0, frm_states)

        # Frame with different padding.
        frm_padding = _create_vframe ("Padding")
        for i in xrange (5):
            btn = ToggleButton ("Padding: %dpx" % (i * 2))
            btn.padding = i * 2
            frm_padding.add_child (btn)
        table.add_child (0, 1, frm_padding)

        # Mnemonics.
        frm_mnemonic = _create_vframe ("Mnemonics")
        btn = ToggleButton ("#Simple Mnemonic")
        btn2 = ToggleButton ("#Activate using <ALT><Underlined Key>")
        frm_mnemonic.add_child (btn, btn2)
        table.add_child (0, 2, frm_mnemonic)

        # Multiline labeled buttons
        frm_multiline = _create_vframe ("Multiline labels")
        strings = ("Single lined ToggleButton", "Two lines on\na ToggleButton",
                   "Two lines with a\n#mnemonic")
        for s in strings:
            button = ToggleButton (s)
            button.child.multiline = True
            frm_multiline.add_child (button)
        table.add_child (1, 0, frm_multiline)

        # Empty buttons with different minimum sizes
        frm_empty = _create_vframe ("Empty Buttons")
        for i in xrange (5):
            button = ToggleButton ()
            button.minsize = (20 * i, 10 * i)
            frm_empty.add_child (button)
        table.add_child (1, 2, frm_empty)

        return table

    if __name__ == "__main__":
        # Initialize the drawing window.
        re = Renderer ()
        re.create_screen (530, 400)
        re.title = "ToggleButton examples"
        re.color = (234, 228, 223)
        re.add_widget (create_button_view ())
        # Start the main rendering loop.
        re.start ()

Example 30. ToggleButton example

### CheckButton

The `CheckButton`, which inherits from the `ToggleButton`, does not bring in any new features. Instead it just uses a different look to display its set state. The state of the `CheckButton` is indicated by a small (usually 10x10 px) square, which is either checked or unchecked.

To create a `CheckButton` widget, you usually will do the same as with the `ToggleButton`.

    button = CheckButton (text)

Below you will find an example to illustrate most of the abilities of the `CheckButton` widget class. You do not need to care about other widgets like the `Frame` class for now as those are explained later on.

You can find the following example as a python script under `examples/checkbutton.py`.

    # CheckButton examples.
    import os
    from ocempgui.widgets import *
    from ocempgui.widgets.Constants import *

    def _create_vframe (text):
        frame = VFrame (Label (text))
        frame.spacing = 5
        frame.align = ALIGN_LEFT
        return frame

    def create_button_view ():
        states = ("STATE_NORMAL", "STATE_ENTERED", "STATE_ACTIVE",
                  "STATE_INSENSITIVE")

        table = Table (2, 3)
        table.spacing = 5
        table.set_row_align (0, ALIGN_TOP)
        table.set_row_align (1, ALIGN_TOP)

        # Frame with the states.
        frm_states = _create_vframe ("States")
        for i, s in enumerate (states):
            btn = CheckButton (s)
            if STATE_TYPES[i] == STATE_INSENSITIVE:
                btn.sensitive = False
            else:
                btn.state = STATE_TYPES[i]
            frm_states.add_child (btn)
        table.add_child (0, 0, frm_states)

        # Frame with different padding.
        frm_padding = _create_vframe ("Padding")
        frm_padding.spacing = 5
        frm_padding.align = ALIGN_LEFT
        for i in xrange (5):
            btn = CheckButton ("Padding: %dpx" % (i * 2))
            btn.padding = i * 2
            frm_padding.add_child (btn)
        table.add_child (0, 1, frm_padding)

        # Mnemonics.
        frm_mnemonic = _create_vframe ("Mnemonics")
        btn = CheckButton ("#Simple Mnemonic")
        btn2 = CheckButton ("#Activate using <ALT><Underlined Key>")
        frm_mnemonic.add_child (btn, btn2)
        table.add_child (0, 2, frm_mnemonic)

        # Multiline labeled buttons
        frm_multiline = _create_vframe ("Multiline labels")
        strings = ("Single lined CheckButton", "Two lines on\na CheckButton",
                   "Two lines with a\n#mnemonic")
        for s in strings:
            button = CheckButton (s)
            button.child.multiline = True
            frm_multiline.add_child (button)
        table.add_child (1, 0, frm_multiline)

        # Empty buttons with different minimum sizes
        frm_empty = _create_vframe ("Empty Buttons")
        for i in xrange (5):
            button = CheckButton ()
            button.minsize = (20 * i, 10 * i)
            frm_empty.add_child (button)
        table.add_child (1, 2, frm_empty)

        return table

    if __name__ == "__main__":
        # Initialize the drawing window.
        re = Renderer ()
        re.create_screen (550, 380)
        re.title = "CheckButton examples"
        re.color = (234, 228, 223)
        re.add_widget (create_button_view ())
        # Start the main rendering loop.
        re.start ()

Example 31. CheckButton example

### RadioButton

`RadioButton` widgets are similar to the `CheckButton` widgets, except that they can grouped, so that only one button of a group can be activated at a time. This is especially helpful, if you need to have the user to choose between a small amount of options.

The creation of a `RadioButton` is done using

    button = RadioButton (text, group)

The additional `group` argument can contain another `RadioButton` object, with which the newly created one should be grouped together.

Alternatively to the `group` argument of the constructor, a `RadioButton` can be assigned to a group after its creation with the group attribute or `set_group()` method.

    button.group = other_radio_button
    button.set_goup (other_radio_button)

It is also possible to go the other way around and to add or remove `RadioButton` widgets from a group with the `add_button()` or `remove_button()` methods of the group.

Given those possibilities a group of four choices can be created like the following example.

    group = RadioButton ("Choice 1")
    button1 = RadioButton ("Choice 2", group)

    button2 = RadioButton ("Choice 3")
    button2.group = group

    button3 = RadioButton ("Choice 4")
    group.add_button (button3)

In contrast to its parent classes, activating a `RadioButton` causes the other buttons in its group to loose their active state.

Below you will find an example to illustrate most of the abilities of the `RadioButton` widget class. You do not need to care about other widgets like the `Frame` class for now as those are explained later on.

You can find the following example as a python script under `examples/radiobutton.py`.

    # RadioButton examples.
    import os
    from ocempgui.widgets import *
    from ocempgui.widgets.Constants import *

    def _create_vframe (text):
        frame = VFrame (Label (text))
        frame.spacing = 5
        frame.align = ALIGN_LEFT
        return frame

    def create_button_view ():
        states = ("STATE_NORMAL", "STATE_ENTERED", "STATE_ACTIVE",
                  "STATE_INSENSITIVE")

        table = Table (2, 3)
        table.spacing = 5
        table.set_row_align (0, ALIGN_TOP)
        table.set_row_align (1, ALIGN_TOP)

        # Frame with the states.
        frm_states = _create_vframe ("States")
        group = None
        for i, s in enumerate (states):
            btn = RadioButton (s, group)
            if i == 0:
                group = btn
            if STATE_TYPES[i] == STATE_INSENSITIVE:
                btn.sensitive = False
            else:
                btn.state = STATE_TYPES[i]
            frm_states.add_child (btn)
        table.add_child (0, 0, frm_states)

        # Frame with different padding.
        frm_padding = _create_vframe ("Padding")
        group = None
        for i in xrange (5):
            btn = RadioButton ("Padding: %dpx" % (i * 2), group)
            if i == 0:
                group = btn
            btn.padding = i * 2
            frm_padding.add_child (btn)
        table.add_child (0, 1, frm_padding)

        # Mnemonics.
        frm_mnemonic = _create_vframe ("Mnemonics")
        btn = RadioButton ("#Simple Mnemonic")
        btn2 = RadioButton ("#Activate using <ALT><Underlined Key>", btn)
        frm_mnemonic.add_child (btn, btn2)
        table.add_child (0, 2, frm_mnemonic)

        # Multiline labeled buttons
        frm_multiline = _create_vframe ("Multiline labels")
        strings = ("Single lined RadioButton", "Two lines on\na RadioButton",
                   "Two lines with a\n#mnemonic")
        group = None
        for i, s in enumerate (strings):
            btn = RadioButton (s, group)
            if i == 0:
                group = btn
            btn.child.multiline = True
            frm_multiline.add_child (btn)
        table.add_child (1, 0, frm_multiline)

        # Empty buttons with different minimum sizes
        group = None
        frm_empty = _create_vframe ("Empty Buttons")
        for i in xrange (5):
            button = RadioButton (None, group)
            button.minsize = (20 * i, 10 * i)
            if i == 0:
                group = button
            frm_empty.add_child (button)
        table.add_child (1, 2, frm_empty)

        return table

    if __name__ == "__main__":
        # Initialize the drawing window.
        re = Renderer ()
        re.create_screen (550, 380)
        re.title = "RadioButton examples"
        re.color = (234, 228, 223)
        re.add_widget (create_button_view ())
        # Start the main rendering loop.
        re.start ()

Example 32. RadioButton example

## Entry boxes

Entry boxes support the input of text or numerical values via the keyboard or similar input devices. They usually support the most common editing operations such as character input, deletion, etc.

### Editable

The `Editable` class is an abstract base class, which takes care of dealing with keyboard events and text caret positioning. It is used as backend for the `Entry` widget class, which will be explained in the next section.

You usually will not create an `Editable` object directly, but rather use it as parent for your own classes.

It can store and operate on (unicode) text through its text attribute. The text usually will be set via this attribute or the `set_text()` method.

    editable.text = "Text"
    editable.set_text ("Text")

It also supports a virtual text caret position, which will be used by its internals to determine the position for editing operations. The caret attribute and `set_caret()` allow you to adjust the caret position.

    editable.caret = 7
    editable.set_caret (7)

Given both the text and caret attribute, the internals of the `Editable` will modify the text of it upon receiving keyboard events, if it has the input focus. Given an `Editable`, which contains the text "This is a Test." and its caret is set to 4, the processing of a pressed key ("D") causes:

1. Check, whether text editing is allowed.

2. If it is, insert a "D" at the fourth position in the text.

3. The text of it now is "ThisD is a Test"

The previous list mentioned a check, whether the text of an `Editable` can be modified. To allow or disallow editing the hold text, you can adjust the value of the editable attribute.

    editable.editable = True
    editable.set_editable (True)

This however only prevents editing operations, which are received as events and not setting the text directly through the text attribute or `set_text()` method.

The `Editable` listens by default to the following signals:

- SIG_KEYDOWN - Invoked, when a key gets pressed.

- SIG_INPUT - Invoked, when the input is validated or aborted using RETURN or ESC.

### Entry

The `Entry` widget is a single line text input box, that inherits from the `Editable` class. It fully supports the `Editable` features and enhances it by mouse event sensitivity.

To create a `Entry` widget, you usually will type

    entry = Entry (text)

`Entry` widgets support a password-like mode, in which any typed character will be displayed as an asterisk ('*').

    entry.password = True

This however does not enahcens security as the typed characters are stored as plain text. Only the display differs.

To allow a better look for some special fonts, the `Entry` can place an additional amount of pixels between its border and the text input area via the padding attribute or `set_padding()` method.

    entry.padding = 5
    entry.set_padding (10)

The gained space will be filled with the background color of the `Entry` by default.

The `Entry` supports the SIG_MOUSEDOWN signal to get the input focus upon a left mouse button press.

Below you will find an example to illustrate most of the abilities of the `Entry` widget class. You do not need to care about other widgets like the `Frame` class for now as those are explained later on.

You can find the following example as a python script under `examples/entry.py`.

    # Entry examples.
    from ocempgui.widgets import *
    from ocempgui.widgets.Constants import *

    def _toggle_password (button, entry):
        entry.password = button.active

    def create_entry_view ():
        states = ("STATE_NORMAL", "STATE_ENTERED", "STATE_ACTIVE",
                  "STATE_INSENSITIVE")

        table = Table (2, 3)
        table.spacing = 5
        table.set_row_align (0, ALIGN_TOP)

        # Frame with the states.
        frm_states = VFrame (Label ("States"))
        frm_states.spacing = 5
        frm_states.align = ALIGN_LEFT
        for i in xrange (len (states)):
            entry = Entry (states[i])
            if STATE_TYPES[i] == STATE_INSENSITIVE:
                entry.sensitive = False
            else:
                entry.state = STATE_TYPES[i]
            frm_states.add_child (entry)
        table.add_child (0, 0, frm_states)

        # Frame with different padding.
        frm_padding = VFrame (Label ("Padding"))
        frm_padding.spacing = 5
        frm_padding.align = ALIGN_LEFT
        for i in xrange (5):
            entry = Entry ("Padding: %dpx" % (i * 2))
            entry.padding = i * 2
            frm_padding.add_child (entry)
        table.add_child (0, 1, frm_padding)

        # Password Mode
        frm_password = VFrame (Label ("Password support"))
        frm_padding.spacing = 5
        entry = Entry ("A password")
        button = ToggleButton ("Password mode")
        button.connect_signal (SIG_TOGGLED, _toggle_password, button, entry)
        frm_password.add_child (entry, button)
        table.add_child (0, 2, frm_password)

        return table

    if __name__ == "__main__":
        # Initialize the drawing window.
        re = Renderer ()
        re.create_screen (400, 400)
        re.title = "Entry examples"
        re.color = (234, 228, 223)
        re.add_widget (create_entry_view ())
        # Start the main rendering loop.
        re.start ()

Example 33. Entry example

## Range widgets

Range widgets denote any widget class, that is based on the abstract `Range` widget class. Those widgets usually support setting a value within a defined value range, such as scaling widgets or scrollbars.

### Range

The `Range` widget class is an abstract class, which enables inheriting classes to set and use value ranges. It can make use of float values, thus providing a high and for most cases exact resolution of values and it supports setting minimum and maximum values as well as stepwise increments.

You usually will not create a `Range` object directly, but inherit from it in your own widget classes. The constructor of a `Range`

    range = Range (minimum, maximum, step)

needs some arguments, which define the minimum range value, the maximum range value and the step range to use for increments or decrements of the `Range`.

The minimum attribute defines the lower limit of the value range it serves, while the maximum attribute defines the upper limit of it. Both can be set either via the attribute or the `set_minimum()` or `set_maximum()` methods.

    if range.minimum < 0:
        range.set_minimum (0)
    if range.maximum > 100:
        range.set_maximum (100)

The step attribute of the `Range` is useful to increment or decrement the value of it in a constant manner. By default it is set to 1.0.

    range.step = 10.0
    range.set_step (-3.2)

It is possible to set the step attribute to a negative value. Although this is confusing in most cases (the in- and decrements will be swapped), it can be useful for the application logic in some (rare) situations.

The value of the `Range` can be read and set via the value attribute and `set_value()` method. It can not grow beyond the upper or lower limit of the `Range`. Assigning a value not within those limitations will let it raise an exception.

    range.value = 4.59
    range.set_value (4.59)

For an efficient usage of the `Range` within loops, etc. the `increase()` and `decrease()` are supplied by it.

    range.increase ()
    range.decrease ()

Those will in- or decrease the value of the range by the set step value, but respect its upper and lower limit. Using those both methods will let you avoid additional exception handling code or limit checks.

The `Range` raises a SIG_VALCHANGED event, whenever its value changed. This means a real value change, reassignments of the same value are ignored. The following example code shows this behaviour.

    def val_changed (range):
       print "The value changed to: %d" % range.value

    range.connect_signal (SIG_VALCHANGED, val_changed, range)
    if range.value != 10.0:
        range.value = 10.0 # Signal handler is invoked.
    range.value = 10.0     # Nothing happens.

### Scale

Scale widgets separate in an abstract `Scale` base class, which mainly contains internal code needed by its both subclasses, the `VScale` and `HScale` widget. A `Scale`, inherited from the `Range`, is a widget that lets you pick a value from a range using a vertical (`VScale`) or horizontal (`HScale`) slider. Those both widgets only differ in their appearance.

To create a `HScale` or `VScale` widget, you typically will use the same constructor syntax as for the `Range` widget.

    hscale = HScale (minimum, maximum, step)
    vscale = VScale (minimum, maximum, step)

As well as for the `Range`, the `minimum` and `maximum` arguments set the upper an lower limit of the value range, while the `step` argument sets the step range and defaults to 1.0.

The most important attributes and methods are already explained in the section called “Range”, so they will not be explained here again.

The `Scale` widgets listen to the three available mouse events,

- SIG_MOUSEDOWN - Invoked, when a mouse button is pressed down on the `Scale`.

- SIG_MOUSEUP - Invoked, when a mouse button is released on the `Scale`.

- SIG_MOUSEMOVE - Invoked, when the mouse moves over the `Scale`.

### ScrollBar

Similar to the `Scale` widget, the `ScrollBar` lets you pick a value from a range, but additionally contains two buttons at its ends, which allow the user to increment or decrement the value stepwise. The `ScrollBar` is usually not used as standalone widget, but instead serves as control in more complex widgets, which need scrolling abilities.

In contrast to the `Scale`, the `ScrollBar` uses a slider with a variable size, which depends on the length of the `ScrollBar` and the maximum value of it. The slider however has a defined minimum size, so that it will not shrink to an unusable size by default.

The procedure to create a `ScrollBar` is similar to the `Scale` and `Range`.

    hscrollbar = HScrollBar (minimum, maximum, step)
    vscrollbar = VScrollBar (minimum, maximum, step)

The most important attributes and methods are already explained in the section called “Scale” and the section called “Range”, so they will not be explained here again.

The `Scrollbar` widgets listen to the three available mouse events,

- SIG_MOUSEDOWN - Invoked, when a mouse button is pressed down on the `ScrollBar`.

- SIG_MOUSEUP - Invoked, when a mouse button is released on the `ScrollBar`.

- SIG_MOUSEMOVE - Invoked, when the mouse moves over the `ScrollBar`.

## Container widgets

Container widgets are able to hold other widgets and take care of drawing them on their own surface. They are mostly used for layout purposes or complex widgets, which consist of several other widgets or which need to add additional functionality to different widget types (like the `ScrolledWindow` widget). They allow to bind one or more widgets as child(ren) to themselves and take over the role as parent widget.

### Bin

The abstract `Bin` class is a container, that is able to hold exactly one child. It allows to bind und unbind a child widget and supports setting an additional padding between its surface borders and the child surface.

You usually will not create a `Bin` object directly, but inherit from it in your own widget classes.

The child of a `Bin` can be set with the child attribute or `set_child()` method. It is not necessary to register the child at an event manager after binding it to the `Bin` as this will set the event manager of the child to its own one.

    label = Label ("Label for a bin")
    bin.set_child (label)
    # No need to set an event manager explicitly for the label.
    bin.manager = eventmanager

This however will not be done, if the child is already bound to an event manager.

For layout purposes the `Bin` can make use of additional pixels to place between its outer surface edges and the child surface. This pixel amount can be modified and used using the padding attribute of the `Bin`. Various inheritors within the widgets module of OcempGUI make heavy use of this attribute to adjust the look of themselves. The following example demonstrates this.

    from ocempgui.widgets import Button, Renderer
    renderer = Renderer ()
    renderer.create_screen (200, 120)
    button_5px = Button ("Button with 5px padding")
    button_5px.topleft = 5, 5
    button_5px.padding = 5

    button_10px = Button ("Button with 10px padding")
    button_10px.topleft = 5, 60
    button_10px.padding = 10

    renderer.add_widget (button_5px, button_10px)
    renderer.start ()

Example 34. Bin.padding example

The following example provides a complete `Bin` implementation which can rotate the visible of its child (and only the surface).

You can find the following example as a python script under `examples/bin.py`.

    # Bin examples.
    import pygame
    from ocempgui.widgets import *
    from ocempgui.widgets.Constants import *

    class PivotBin (Bin):
        """PivotBin (widget) -> OwnBin

        A Bin implementation example class.

        This class does not support real rotations of widgets. Instead it
        simply rotates their image surface and displays it. Any other
        behaviour and information of the widget stay the same. Thus event
        capable widgets will not work correctly.
        """
        def __init__ (self):
            Bin.__init__ (self)
            self._orientation = ORIENTATION_HORIZONTAL

        def set_orientation (self, orientation=ORIENTATION_HORIZONTAL):
            """P.set_orientation (...) -> None

            Sets the orientation of the attached child.
            """
            if orientation not in ORIENTATION_TYPES:
                raise ValueError("orientation must be a value of ORIENATION_TYPES")
            self._orientation = orientation
            self.dirty = True

        def draw_bg (self):
            width, height = self.padding, self.padding
            cls = self.__class__

            if self.child:
                width += self.child.width
                height += self.child.height
                if self.orientation == ORIENTATION_VERTICAL:
                    # Swap width and height on demand
                    width, height = height, width

            # Guarantee the set minimum and maximum sizes.
            width, height = self.check_sizes (width, height)
            surface = base.GlobalStyle.engine.draw_rect (width, height, self.state,
                                                         cls, self.style)
            return surface

        def draw (self):
            """Draws the PivotBin and its child according to the set orientation."""
            Bin.draw (self)
            if self.child:
                rect = self.image.get_rect ()
                self.child.center = rect.center
                if self.orientation == ORIENTATION_VERTICAL:
                    # Rotate the child image on demand.
                    image = pygame.transform.rotate (self.child.image, 90)
                    rotate_rect = image.get_rect ()
                    rotate_rect.center = rect.center
                    self.image.blit (image, rotate_rect)
                else:
                    self.image.blit (self.child.image, self.child.rect)

        orientation = property (lambda self: self._orientation,
                                lambda self, var: self.set_orientation (var),
                                doc = "The orientation of the child.")

    def rotate_bin (bin, button):
        # Set the Bin orientation and replace the button.
        if bin.orientation == ORIENTATION_HORIZONTAL:
            bin.orientation = ORIENTATION_VERTICAL
        else:
            bin.orientation = ORIENTATION_HORIZONTAL
        button.topleft = bin.left, bin.bottom + 10

    if __name__ == "__main__":
        bin = PivotBin ()
        bin.topleft = 10, 10
        bin.child = Label ("Simple label in PivotBin")

        button = Button ("Switch orientation")
        button.topleft = bin.left, bin.bottom
        button.connect_signal (SIG_CLICKED, rotate_bin, bin, button)

        # Initialize the drawing window.
        re = Renderer ()
        re.create_screen (300, 300)
        re.title = "Bin implementation example"
        re.color = (234, 228, 223)
        re.add_widget (bin, button)

        # Start the main rendering loop.
        re.start ()

Example 35. Bin example

### Container

The abstract `Container` widget class is similar to the `Bin` class, except that it can hold more than one widget.

As well as with the `Bin`, you usually will not create a `Container` object directly, but inherit from it in your own class.

The children can be added using `add_child()`, which allows to add multiple children at once, or the `insert_child()` method.

    # Add a single child.
    container.add_child (label1)

    # Add multiple children at once.
    container.add_child (label1, button1, label2, entry1)

    # Insert a child at a specific position
    container.insert_child (1, entry2)

Dependant on the `Container` implementation, `insert_child()` can cause the inserted child to appear at a specific position.

The removal of children can be done with one widget at a time only using the `remove_child()` method of the `Container`.

    # Only one child can be removed at a time.
    container.remove_child (button1)

You also can set the children directly using the children attribute. The `Container` will remove all its children first and then add the new list of widgets. Simply setting the children to None will remove all the widgets of the `Container`.

    # Set a list of widgets as children of a container.
    container.children = [label1, button1, entry1]

    # Remove all children of the container.
    container.children = None

Besides the padding attribute, which was already explained in the section called “Bin” the `Container` has a spacing attribute, which indicates the pixel amount to place between its children.

    container.spacing = 10

The `Frame` examples in the later section will show you possible concrete results.

TODO: provide implementation examples

### Box

The `Box` widgets are `Container`s which allow an absolute placement of their attached children. This enables you to let widgets overlap or place them next o each other according to your needs while keeping them relative to other widgets without extensive position calculations. You could e.g. place a `Box` into a `Frame` so that the contents of the `Box` are aligned relative to other widgets of the `Frame` while being positioned exactly as you need.

To create a `Box` you have to call its constructor with the size it should occupy.

    box = Box (100, 100)

Now widgets can be added to it using the typical `Container` methods. The topleft coordinates of the attached widgets are used to position them within the Box. Thus a `Button` with the topleft value of 10, 10 will be placed 10 pixels from the topleft corner of the `Box`.

    box = Box (100, 100)
    button = Button ("A Button")
    button.topleft = 10, 10
    box.add_child (button)

### Note

The `Box` widget class does not make use of the padding and spacing attributes of its `Container` parent class. It also does not resize itself, when a widget leaves its visible area or occupies more space than the `Box`.

Below you will find an example to illustrate most of the abilities of the `Box` widget classes. You do not need to care about other widgets like the `VFrame` class for now as those are explained later on.

You can find the following example as a python script under `examples/box.py`.

    # Box examples.
    from ocempgui.widgets import *
    from ocempgui.widgets.Constants import *

    def create_box_view ():
        frame = VFrame (Label ("Box example"))
        frame.topleft = 10, 10

        # The Box with 200x200 pixels in size.
        box = Box (200, 200)

        # Widgets to place into it.
        label = ImageLabel ("image.png")
        label.topleft = 10, 10

        button = Button ("A Button")
        button.topleft = 30, 30

        frame1 = VFrame (Label ("A VFrame"))
        frame1.add_child (Label ("Label in the VFrame"))
        frame1.topleft = 60, 80

        chk = CheckButton ("A CheckButton")
        chk.topleft = 130, 110

        box.children = label, button, frame1, chk
        frame.add_child (box)

        return frame

    if __name__ == "__main__":
        # Initialize the drawing window.
        re = Renderer ()
        re.create_screen (300, 300)
        re.title = "Box examples"
        re.color = (234, 228, 223)
        re.show_layer_info = True
        re.add_widget (create_box_view ())
        # Start the main rendering loop.
        re.start ()

Example 36. Box example

### Frames

`Frame` widgets are `Container`s, that support drawing a decorative border and title widget around their children. The basic `Frame` class is an abstract class, which defines the common attributes and methods for its inheritors, while the `HFrame` and `VFrame` widgets are concrete implementations, that place their children horizontally or vertically. Both subclasses only differ in the placing behaviour of their widgets and the basic aligning possibilities, so that, if not stated otherwise, the following examples always apply to both widget types, although the `HFrame` is used.

The creation of a `HFrame` is done using

    frame = HFrame ()
    frame = HFrame (widget)

The difference between both is, that the first constructor does not set up a title widget for the `Frame`. The title widget can be any valid `BaseWidget` subclass and typically be placed at the topleft corner of the `Frame`. If no title widget is supplied, a complete border will be drawn around the `Frame`, while a set title widget will discontinue that border at the topleft corner. You can change or set the title widget at any later time. A few possibilities should be shown here.

    frame = HFrame (Label ("A title label"))
    frame.widget = Button ("Button as frame title")
    frame.set_widget (VFrame (Label ("Frame in a frame")))

To adjust the look of the `Frame`, it is possible to change its border style using the border attribute

    frame.border = BORDER_NONE
    frame.set_border (BORDER_SUNKEN)

and to change the alignment of its packed children using the align attribute.

    frame.align = ALIGN_TOP
    frame.align = ALIGN_LEFT

Here a diversion between the `HFrame` and `VFrame` has to be made, because each one only supports a subset of the alignment possibilities. The `HFrame` widget natively supports aligning its children at the top or bottom only

    hframe.align = ALIGN_TOP
    hframe.set_align (ALIGN_BOTTOM)

while the `VFrame` supports only the left and right alignment.

    vframe.align = ALIGN_LEFT
    vframe.set_align (ALIGN_RIGHT)

Both use no alignment (ALIGN_NONE) by default, which causes their children to be centered relatively to each other.

Below you will find an example to illustrate most of the abilities of the `Frame` widget classes. You do not need to care about other widgets like the `Table` class for now as those are explained later on.

You can find the following example as a python script under `examples/frame.py`.

    # Frame examples.
    import os
    from ocempgui.widgets import *
    from ocempgui.widgets.Constants import *

    def create_frame_view ():
        table = Table (2, 3)
        table.topleft = 5, 5
        table.spacing = 5

        # Create and display two 'standard' frames.
        hframe = HFrame (Label ("Horizontal Frame"))
        table.add_child (0, 0, hframe)

        lbl = Label ("Vertical Frame" + os.linesep + "with 5 px spacing")
        lbl.multiline = True
        vframe = VFrame (lbl)
        vframe.spacing = 5
        table.add_child (0, 1, vframe)

        for i in xrange(3):
            btn = Button ("Button %d" % i)
            hframe.add_child (btn)
            btn2 = Button ("Button %d" % i)
            vframe.add_child (btn2)

        # Create framed frames.
        framed1 = VFrame (Label ("VFrame"))
        framed2 = HFrame ()
        framed3 = VFrame (Label ("VFrame as HFrame.widget"))
        framed3.add_child (Label ("Child of a VFrame"))
        framed2.widget = framed3
        framed2.add_child (Button ("Button 1"), Button ("Button 2"))
        button = Button ("Simple Button")
        framed1.add_child (framed2, button)
        table.add_child (1, 0, framed1)

        # Create a Frame with alignment.
        frame_align = VFrame (Label ("VFrame with right alignment"))
        frame_align.align = ALIGN_RIGHT
        label1 = Label ("Label")
        label2 = Label ("Even longer label")
        button = CheckButton ("A CheckButton")
        frame_align.add_child (label1, label2, button)
        table.add_child (1, 1, frame_align)

        # Add insensitive frames.
        hframe = HFrame (Label ("Insensitive HFrame"))
        hframe.sensitive = False
        table.add_child (0, 2, hframe)

        vframe = VFrame (Label ("Insensitive VFrame"))
        vframe.sensitive = False
        table.add_child (1, 2, vframe)

        for i in xrange(3):
            btn = Button ("Button %d" % i)
            hframe.add_child (btn)
            btn2 = Button ("Button %d" % i)
            vframe.add_child (btn2)

        return table

    if __name__ == "__main__":
        # Initialize the drawing window.
        re = Renderer ()
        re.create_screen (600, 300)
        re.title = "Frame examples"
        re.color = (234, 228, 223)
        re.add_widget (create_frame_view ())

        # Start the main rendering loop.
        re.start ()

Example 37. Frame example

### Table

`Table` widgets, which inherit from the `Container` class, allow a table-like placement of their children in rows and columns. The children can be placed in the table cells and each cell supports an individual alignment.

The `Table` constructor expects the row and column dimensions to set up for the table, so that

    table = Table (2, 2)
    table2 = Table (3, 5)

would create two tables. The first would be a quadratic one with two rows, of which each serves two columns, which allows to place four children in it, the second sets up three rows with 5 columns in each of it allowing to hold up to fifteen children.

Adding children is different from the usual `Container` methods. The `Table` needs the additional information, in which cell to place the child. Thus instead of using

    table.add_child (child_widget1, child_widget2) # This does not work!

you have to add children by identifying the row and column to place them into.

    table.add_child (row, column, child_widget1)
    table.add_child (row1, column1, child_widget2)

Removing children from the `Table` in contrast works in the same way you already learned about in the section called “Container”.

### Note

Assigning the children attribute of the `Table` with a list of widgets adds the children row for row to it.

As said above, each cell of the `Table` supports using an own alignment, which can be set with the `set_align()` method.

    table.set_align (0, 1, ALIGN_TOP)
    table.set_align (1, 1, ALIGN_LEFT)

Different alignments can be combined, although not any case makes sense and some alignment combinations conflict with each other. Thus the table uses a different aligning priority, which is explained in detail in the `Table` documentation.

    # Aligning the child at the topleft.
    table.set_align (0, 1, ALIGN_TOP | ALIGN_LEFT)

    # Conflicting alignments, thus using the higher priority of ALIGN_TOP.
    table.set_align (0, 1, ALIGN_TOP | ALIGN_BOTTOM)

    # Again a conflict. ALIGN_NONE has the lowest priority, thus it will be
    # left aligned.
    table.set_align (0, 1, ALIGN_LEFT | ALIGN_NONE)

Two additional methods allow you to align a complete column or row using a specific alignment value.

    table.set_row_align (row, alignment)
    table.set_column_align (column, alignment)

Below you will find an example to illustrate most of the abilities of the `Table` widget class.

You can find the following example as a python script under `examples/table.py`.

    # Table examples.
    from ocempgui.widgets import Renderer, Table, Label, Button
    from ocempgui.widgets.Constants import *

    def create_table_view ():
        # Crate and display a Table.
        table = Table (9, 2)
        table.spacing = 5
        table.topleft = 5, 5

        label = Label ("Nonaligned wide Label")
        table.add_child (0, 0, label)
        table.add_child (0, 1, Button ("Simple Button"))

        label = Label ("Top align")
        table.add_child (1, 0, label)
        table.set_align (1, 0, ALIGN_TOP)
        table.add_child (1, 1, Button ("Simple Button"))

        label = Label ("Bottom align")
        table.add_child (2, 0, label)
        table.set_align (2, 0, ALIGN_BOTTOM)
        table.add_child (2, 1, Button ("Simple Button"))

        label = Label ("Left align")
        table.add_child (3, 0, label)
        table.set_align (3, 0, ALIGN_LEFT)
        table.add_child (3, 1, Button ("Simple Button"))

        label = Label ("Right align")
        table.add_child (4, 0, label)
        table.set_align (4, 0, ALIGN_RIGHT)
        table.add_child (4, 1, Button ("Simple Button"))

        label = Label ("Topleft align")
        table.add_child (5, 0, label)
        table.set_align (5, 0, ALIGN_TOP | ALIGN_LEFT)
        table.add_child (5, 1, Button ("Simple Button"))

        label = Label ("Topright align")
        table.add_child (6, 0, label)
        table.set_align (6, 0, ALIGN_TOP | ALIGN_RIGHT)
        table.add_child (6, 1, Button ("Simple Button"))

        label = Label ("Bottomleft align")
        table.add_child (7, 0, label)
        table.set_align (7, 0, ALIGN_BOTTOM |ALIGN_LEFT)
        table.add_child (7, 1, Button ("Simple Button"))

        label = Label ("Bottomright align")
        table.add_child (8, 0, label)
        table.set_align (8, 0, ALIGN_BOTTOM |ALIGN_RIGHT)
        table.add_child (8, 1, Button ("Simple Button"))

        return table

    if __name__ == "__main__":
        # Initialize the drawing window.
        re = Renderer ()
        re.create_screen (250, 350)
        re.title = "Table examples"
        re.color = (234, 228, 223)
        re.add_widget (create_table_view ())
        # Start the main rendering loop.
        re.start ()

Example 38. Table example

### ScrolledWindow

`ScrolledWindow` widgets are `Bin` widgets that add scrolling abilities to their attached child. This is extremely useful for situations, in which the widget to scroll should not exceed a specific size, but has to display all of its data. Putting such a widget in a `ScrolledWindow` allows you to respect this specific size, while the widget can grow as it wants.

You create a `ScrolledWindow` using

    window = ScrolledWindow (width, height)

where `width` and `height` denote values for the size attribute of the `ScrolledWindow`. The newly created `ScrolledWindow` will not exceed this size by default.

The widget, which needs to be scrolled is packed into the `ScrolledWindow` the usual `Bin` way.

    window.child = widget_to_scroll

To allow a flexibly scrolling behaviour, you can adjust the scrolling attribute to make the `ScrolledWindow` automatic scrolling, always scrolling or never scrolling.

    window.scrolling = SCROLL_ALWAYS
    window.scrolling = SCROLL_NEVER
    window.scrolling = SCROLL_AUTO

This setting influences the visibility of the both `ScrollBar` controls attached to the window and is described in details in the `set_scrolling()` method documentation.

You also can influence the scrollbars of the `ScrolledWindow` programmatically.

    window.vscrollbar.value = 0
    window.hscrollbar.value = window.vscrollbar.maximum

The above code would cause the `ScrolledWindow` to scroll to the topright of its attached child.

The `ScrolledWindow` widget natively listens to two signals to support better navigation possibilities. Those are

- SIG_MOUSEDOWN - Invoked, when a mouse button is pressed down on the ScrolledWindow.

- SIG_KEYDOWN - Invoked, when a key gets pressed.

### ScrolledList

The `ScrolledList` widget class can be used to display and manage collections in a list-style look and feel. Technically it is a `ScrolledWindow`, which holdes a `ListViewPort` that takes care of displaying the list contents.

As the `ScrolledWindow` the `ScrolledList` supports different scrolling types and anything else, while the keyboard and mouse behaviour differ slightly to match the needs of list browsing.

To create a `ScrolledList` you have to supply the sizing dimensions and an optional collection, which makes up the contents.

    scrolledlist = ScrolledList (width, height, collection=None)

If the collection is not specified, a basic `ListItemCollection` (explained later) object is automatically bound to it. The `ScrolledList` however only accepts collections, which inherit from the `ListItemCollection`.

Items can be added and removed dynamically to the list using the items property.

    for no in xrange (10):
        scrolledlist.items.append (TextListItem ("Item no. %d" % no))

    # Last one was too much.
    scrolledlist.items.remove (scrolledlist.items[-1])

The bound `ListItemCollection` wraps a list and fully supports all important operations of, including slicing, indexed item access and sorting. More details about the `ListItemCollection` can be found in the section called “ListItemCollection”.

### FileList

The `FileList` widget is useful to display filesystem contents in a list-style manner. It supports the distinction between different filetypes through the `FileListItem` item type and allows you to browse filesystem contents.

As the `ScrolledList`, from which the `FileList` inherits, you need to pass the size dimensions it should occupy and optionally the initial starting directory to list the contents of.

    filelist = FileList (200, 400, "/usr/home")

If the initial directory remains unset, the `FileList` will list the contents of the current directory as set in `os.curdir`.

It allows to list directories programmatically through the directory attribute and `set_directory()` method.

    filelist.directory = "C:\"
    filelist.set_directory ("/tmp")

If the user however has not the correct access rights for a specific directory, the `FileList` will not list it, but instead provide an acoustic signal using `print "\a"`.

The `FileList` additionally supports the SIG_DOUBLECLICKED signal to allow changing directories interactively. Of course own methods can be bound to it.

## Windows and Dialogs

The windows of `ocempgui.widgets` are containers, that have an own caption bar, can be moved within the main pygame window and allow the user to collapse them to their caption bar. They can be drawn on top of other widgets by adjusting their depth attribute as already explained in the section called “Common widget operations - the BaseWidget”.

### Window

The base for all the different window types is the `Window` class. It is a `Bin` container with the additional ability to collapse itself to its caption bar.

To create a `Window` you can simply call its constructor and provide an optional title text, that will be used as caption.

    window = Window ("My new window")

The title can be retrieved or set at any later time with the title attribute.

    window.title = "A new title!"

As already mentioned above, the `Window` allows the user to minimize it (and of course restore it), which is also possible in your own code.

    if not window.minimized:
        window.minimize (True)

By overriding the `minimize()` method you can prevent the user from doing so, if you do not want it for a certain window.

You can align the child of the window using the align attribute. Different alignments can be combined, although not any case makes sense and some alignment combinations conflict with each other.

    # Align the child at the top.
    window.align = ALIGN_TOP

    # Align the child at the bottom left.
    window.align = ALIGN_BOTTOM | ALIGN_LEFT

    # Invalid alignment, ALIGN_BOTTOM has a higher priority, thus
    # the child will be aligned at the bottom.
    window.align = ALIGN_TOP | ALIGN_BOTTOM

Thus the `Window` uses an aligning priority, which is explained in detail in the `Window` documentation.

The `Window` widget by default listens to the following signals:

- SIG_MOUSEDOWN - Invoked, when a mouse button is pressed down on the Window.

- SIG_MOUSEUP - Invoked, when a mouse button is released on the Window.

- SIG_MOUSEMOVE - Invoked, when the mouse moves over the Window area.

Below you will find an example of the `Window` widget class. You do not need to care about the `DialogWindow` class for now as this is explained in the next section.

You can find the following example as a python script under `examples/window.py`.

    # Window examples.
    from ocempgui.widgets import *
    from ocempgui.widgets.Constants import *

    def _destroy_dialog (window):
        window.child.text = "#Close"

    def create_window_view ():
        # Create and display a simple window.
        window = Window ("Simple window")
        window.child = Button ("#Not clickable")
        window.child.connect_signal (SIG_CLICKED, window.destroy)
        window.topleft = 5, 5
        window.depth = 1

        # Create dialog window.
        dialog = DialogWindow ("Modal dialog window")
        dialog.child = Button ("#Close first to use other widgets")
        dialog.child.connect_signal (SIG_CLICKED, _destroy_dialog, window)
        dialog.child.connect_signal (SIG_CLICKED, dialog.destroy)
        dialog.topleft = 100, 5
        dialog.depth = 2

        return window, dialog

    if __name__ == "__main__":
        # Initialize the drawing window.
        re = Renderer ()
        re.create_screen (400, 200)
        re.title = "Window examples"
        re.color = (234, 228, 223)
        re.show_layer_info = True
        re.add_widget (*create_window_view ())
        # Start the main rendering loop.
        re.start ()

Example 39. Window example

### DialogWindow

The `DialogWindow` is a modal `Window` widget, that grabs all events that are sent through the event manager it is attached to. The user will not be able to interact with other event capable elements until the `DialogWindow` is destroyed. Widgets, that are attached to it of course will still be notified.

The `DialogWindow` does not offer any new features besides those it incorporates from its parent class(es). To create a new `DialogWindow` you use the same constructor syntax as for the `Window`.

    window = DialogWindow ("A new DialogWindow")

You can find an example of the `DialogWindow` in Example 39, “Window example”.

### GenericDialog

It is often needed to know about how the user interacted with a certain dialog. Creating various `Buttons` with different callbacks or one callback, in which the buttons are distinguished is of course possible, but finding a safe distinction mode is a more complex task. You might argue, that you could check the text of the `Button`, but that only will work, if you do not want to offer localized version of you program.

To circumvent this and other issues the `GenericDialog` widget class was created. It allows you to associate different states with the buttons you want to place on it.

To create a `GenericDialog` you have to pass two lists to its constructor, one containing the `Button` widgets you want to display and one with the result states to associate with.

    list1 = [Button ("OK"), Button("Cancel")]
    list2 = [DLGRESULT_OK, DLGRESULT_CANCEL]
    dialog = GenericDialog ("Title", list1, list2)

The order of the elements in both list is of value as this will

- influence the order of the buttons from left to right,

- influence the results of the buttons.

This means, that the first `Button` in the list will be displayed at the leftmost of all other `Buttons`, while it will be associated with the first item of the result list.

To allow a more flexible button and result behaviour (as needed in wizard dialogs for example), you can place new buttons and results at runtime on the dialog.

    newlist1 = [Button ("Close"), Button ("Help")]
    newlist2 = [DLGRESULT_CLOSE, DLGRESULT_USER]
    dialog.set_buttons (newlist1, newlist2)

Now all you have to do is to connect your `GenericDialog` with a callback for the SIG_DIALOGRESPONSE signal, it listens to.

    def my_callback (result, dlg):
        if result == DLGRESULT_CLOSE:
            dlg.destroy ()
        elif result == DLGRESULT_USER:
            ...

    dialog,connect_signal (SIG_DIALOGRESPONSE, my_callback, dialog)

As you can see in the above example, this kind of dialog will not destroy itself, but instead has to be destroyed programmatically.

To place your own widgets and contents in the dialog, you can use the content attribute, which is a `VFrame`.

    label1 = Label ("Label 1")
    entry = Entry ("Hello world")
    dialog.content.add_child (label1, entry)
    ...

All said about the `Frame` widget type applies to this one, too.

Below you will find an example of the `GenericDialog` widget class.

You can find the following example as a python script under `examples/genericdialog.py`.

    # GenericDialog examples.
    from ocempgui.widgets import *
    from ocempgui.widgets.Constants import *

    def _close (result, dialog, label):
        if result == DLGRESULT_OK:
            label.text = "You pressed OK!"
        elif result == DLGRESULT_CANCEL:
            label.text = "You pressed Cancel!"
        elif result == DLGRESULT_CLOSE:
            dialog.destroy ()

    def create_dialog_view ():
        buttons = [Button ("#OK"), Button ("#Cancel"), Button ("Clo#se")]
        results = [DLGRESULT_OK, DLGRESULT_CANCEL, DLGRESULT_CLOSE]
        dialog = GenericDialog ("Generic dialog", buttons, results)
        lbl = Label ("Press the buttons to see the action.")
        dialog.content.add_child (lbl)
        dialog.connect_signal (SIG_DIALOGRESPONSE, _close, dialog, lbl)
        dialog.topleft = 30, 30
        dialog.depth = 1
        return dialog

    if __name__ == "__main__":
        # Initialize the drawing window.
        re = Renderer ()
        re.create_screen (300, 300)
        re.title = "GenericDialog examples"
        re.color = (234, 228, 223)
        re.add_widget (create_dialog_view ())
        # Start the main rendering loop.
        re.start ()

Example 40. GenericDialog example

### FileDialog

The `FileDialog` widget allows the user to choose files and directories from a `FileList` and can return those easily by a corresponding method. It also includes an `Entry` widget at the top, which keeps track of the current location and lets the user change the directory path quickly.

To create a `FileDialog` you have would type something like

    dialog = FileDialog ("Select a file...", [Button ("OK")], [DLGRESULT_OK])

The first argument provides the title of the dialog, while the next two ones take the buttons and results for the dialog as already explained in the section called “GenericDialog”. There is also an optional last argument, which can set the initial directory to list as explained in the section called “FileList”.

The selected file and directory entries can be received easily using the `get_filenames()` method.

    selection = dialog.get_filenames()

The selection entries will contain the absolute path to those filenames.

Below you will find an example of the `FileDialog` widget class.

You can find the following example as a python script under `examples/filedialog.py`.

    # FileDialog examples.
    import os
    from ocempgui.widgets import *
    from ocempgui.widgets.Constants import *

    def _set_files (result, dialog, entry):
        string = ""
        if result == DLGRESULT_OK:
            string = "".join(["\"%s\" " % f for f in dialog.get_filenames ()])
        else:
            string = "Nothing selected"
        dialog.destroy ()
        entry.text = string

    def _open_filedialog (renderer, entry):
        buttons = [Button ("#OK"), Button ("#Cancel")]
        buttons[0].minsize = 80, buttons[0].minsize[1]
        buttons[1].minsize = 80, buttons[1].minsize[1]
        results = [DLGRESULT_OK, DLGRESULT_CANCEL]

        dialog = FileDialog ("Select your file(s)", buttons, results)
        dialog.depth = 1 # Make it the top window.
        dialog.topleft = 100, 20
        dialog.filelist.selectionmode = SELECTION_MULTIPLE
        dialog.connect_signal (SIG_DIALOGRESPONSE, _set_files, dialog, entry)
        renderer.add_widget (dialog)

    def create_file_view (renderer):
        table = Table (1, 2)

        hframe = HFrame (Label ("FileList"))
        hframe.add_child (FileList (200, 200))
        table.add_child (0, 0, hframe)

        hframe2 = HFrame (Label ("FileDialog"))
        label = Label ("Selection:")
        entry = Entry ()
        entry.minsize = 200, entry.minsize[1]
        button = Button ("#Browse")
        button.connect_signal (SIG_CLICKED, _open_filedialog, renderer, entry)
        hframe2.add_child (label, entry, button)
        table.add_child (0, 1, hframe2)

        table.set_row_align (0, ALIGN_TOP)
        return table

    if __name__ == "__main__":
        # Initialize the drawing window.
        re = Renderer ()
        re.create_screen (550, 300)
        re.title = "FileDialog examples"
        re.color = (234, 228, 223)
        re.add_widget (create_file_view (re))
        # Start the main rendering loop.
        re.start ()

Example 41. FileDialog example

## Miscellaneous Widgets

### ImageMap

The `ImageMap` is a widget, that can display any type of image, pygame can handle, and supports different mouse events.

In contrast to the `ImageButton` it does not react visually upon those events, but can store the last event, that occured as well as providing the relative position coordinates of the event.

To create an `ImageMap`, you have to provide an image surface or filename similar to the `ImageButton` constructor.

    imagemap = ImageMap ("path/to/an/image.png")
    imagemap = ImageMap (pygame_surface)

Of course the image can be changed at any time using the picture attribute or `set_picture()` method.

Below you will find an example of the `ImageMap` widget class.

You can find the following example as a python script under `examples/imagemap.py`.

    # ImageMap examples.
    import os
    from ocempgui.widgets import *
    from ocempgui.widgets.Constants import *

    def _get_type (eventtype):
        if eventtype == SIG_MOUSEDOWN:
            return "SIG_MOUSEDOWN"
        elif eventtype == SIG_MOUSEUP:
            return "SIG_MOUSEUP"
        elif eventtype == SIG_MOUSEMOVE:
            return "SIG_MOUSEMOVE"
        else:
            return "Unknown signal"

    def _got_mouseevent (event, imagemap, labels):
        labels[0].text = "Signal: %s" % _get_type (imagemap.last_event.signal)
        if imagemap.last_event.signal != SIG_MOUSEMOVE:
            labels[1].text = "Button: %d" % imagemap.last_event.data.button
        else:
            labels[1].text = "Button: None"
        labels[2].text = "Event pos: %s" % str (imagemap.last_event.data.pos)
        labels[3].text = "Rel. pos: %s" % str (imagemap.relative_position)

    def _create_vframe (text):
        frame = VFrame (Label (text))
        frame.spacing = 5
        frame.align = ALIGN_LEFT
        return frame

    def create_imagemap_view ():
        frm_map = _create_vframe ("ImageMap")

        imagemap = ImageMap ("image.png")

        lbl_desc = Label ("Move the mouse over the ImageMap and" + os.linesep +
                          "press the mouse buttons to interact with it.")
        lbl_desc.multiline = True

        lbl_results = [Label ("Signal:"), Label ("Button:"), Label ("Event pos:"),
                       Label ("Rel. pos:")]
        for label in lbl_results:
            label.create_style()["fgcolor"][STATE_NORMAL] = (255, 0, 0)
        imagemap.connect_signal (SIG_MOUSEDOWN, _got_mouseevent, imagemap,
                                 lbl_results)
        imagemap.connect_signal (SIG_MOUSEMOVE, _got_mouseevent, imagemap,
                                 lbl_results)
        imagemap.connect_signal (SIG_MOUSEUP, _got_mouseevent, imagemap,
                                 lbl_results)

        frm_map.add_child (imagemap, lbl_desc, *lbl_results)
        return frm_map

    if __name__ == "__main__":
        # Initialize the drawing window.
        re = Renderer ()
        re.create_screen (250, 220)
        re.title = "ImageMap examples"
        re.color = (234, 228, 223)
        re.add_widget (create_imagemap_view ())
        # Start the main rendering loop.
        re.start ()

Example 42. ImageMap example

### ProgressBar

The `ProgressBar` is a non-interactive widget class, that uses a horizontal bar to display operation efforts. Its value range reaches from 0.0 to 100.0.

To create a `ProgressBar` widget, you simply invoke its constructor with no arguments.

    bar = ProgressBar ()

Similar to the `Range` widget class, the `ProgressBar` supports the step and `set_step()` methods to set the step range for continouos increments/decrements

    bar.step = 1.4
    bar.set_step (10)

    # Increment/decrement the bar value by the currently set step range.
    while process_runs:
        bar.increment ()           # or bar.decrement ()
        ...

as well as setting its current value directly using the value attribute.

    bar.value = 50.0

You can optionally display a short amount of text centered on it, which can be set with the text attribute or `set_text()` method.

    bar.text = "Processing data..."
    bar.set_text ("Please wait...")

You can find the following example as a python script under `examples/progressbar.py`.

    # ProgressBar examples.
    from ocempgui.widgets import *
    from ocempgui.widgets.Constants import *

    def _update_bar (bar, button):
        if bar.value == 0:
            while bar.value < 100:
                bar.increase ()
            button.text = "Clean the progressbar"
        else:
            while bar.value > 0:
                bar.decrease ()
            button.text = "Fill the progressbar"

    def _update_text (bar):
        bar.text = "%.2f" % bar.value + "%"

    def _create_vframe (text):
        frame = VFrame (Label (text))
        frame.spacing = 5
        frame.align = ALIGN_LEFT
        return frame

    def create_progressbar_view ():
        table = Table (1, 3)
        table.spacing = 5

        # Create and display a simple ProgressBar.
        frame = _create_vframe ("ProgressBar")
        progress = ProgressBar ()
        progress.step = 0.5

        # Create a button to start filling.
        btn = Button ("#Fill the ProgressBar")
        btn.connect_signal ("clicked", _update_bar, progress, btn)
        frame.add_child (progress, btn)
        table.add_child (0, 0, frame)

        # ProgressBar with text.
        frame = _create_vframe ("Progressbar with text")
        progress = ProgressBar ()
        progress.text = "0.00%"
        progress.step = 0.5
        progress.connect_signal (SIG_VALCHANGED, _update_text, progress)

        # Create a button to start filling.
        btn = Button ("Fill the ProgressBar")
        btn.connect_signal ("clicked", _update_bar, progress, btn)
        frame.add_child (progress, btn)
        table.add_child (0, 1, frame)

        # Insensitive progressbar.
        frame = _create_vframe ("Insensitive Progressbar")
        progress = ProgressBar ()
        progress.value = 50.0
        progress.text = "50.00%"
        progress.sensitive = False
        frame.add_child (progress)
        table.add_child (0, 2, frame)

        return table

    if __name__ == "__main__":
        # Initialize the drawing window.
        re = Renderer ()
        re.create_screen (450, 150)
        re.title = "ProgressBar examples"
        re.color = (234, 228, 223)
        re.add_widget (create_progressbar_view ())
        # Start the main rendering loop.
        re.start ()

Example 43. ProgressBar example

### Diagram

The `Diagram` class is an abstract base class for Diagram like widgets such as the `Graph2D`. It provides interfaces to create statistical diagrams easily, be it graphs, bar and pie charts or whatever else.

You usually will not create an `Diagram` object directly, but rather use it as parent for your own classes.

TODO

### Graph2D

The `Graph2D` class allows you to plot two-diemensional graphs using a cartesian coordinate plane. You can choose the names of the axes, scale units and units to display and set up the evaluation function for plotting the graph freely.

To create a `Graph2D` widget, you simply invoke its constructor with the minimum size to occupy by the widget.

    graph = Graph2D (400, 400)

The default names of the axes are "x" and "y". They can be changed using the axes attribute and `set_axes` method.

    graph.axes = "t", "v" # Set velocity related to time.
    graph.set_axes ("t", "v")

To set the scale units to display for the horizontal and vertical axis, the scale_units attribute and `set_scale_units()` method can be used. The first value is used for the horizontal, the second for the vertical axis.

    graph.scale_units = ("cm", "kp")
    graph.set_scale_units ("cm", "kp")

To show or hide the scale units and axes names on the graph, the show_names attribute and `set_show_names` method are used. The names and units are usually diplayed on the right of the axes.

    graph.show_names = True # Show the names
    graph.set_show_names (False) # Do not display them.

The distance from one unit to another can be set using the units and `set_units` method. The distance is given in pixels and defaults to 10 to 10.

    graph.units = 10, 25 # Set 10 px for the horizontal units, 25 for vertical
    graph.set_units (10, 25)

You can rotate the graph clockwise by 90 degrees by adjusting the orientation attribute. The default is a horizontal orientation.

    graph.orientation = ORIENTATION_VERTICAL # Rotate the graph
    grap.set_orientation (ORIENTATION_HORIZONTAL)

TODO

You can find the following example as a python script under `examples/graph2d.py`.

    # Graph2D examples.
    import sys, math
    from ocempgui.widgets import *
    from ocempgui.widgets.Constants import *
    try:
        import Numeric
    except ImportError:
        Numeric = None
        try:
            import numpy
        except ImportError:
            print "Numeric or numpy could not be found"
            sys.exit (-1)

    __function = "func_1"

    def change(graph):
        global __function
        if __function == "func_1":
            graph.eval_func = lambda x: x / ((- 3 * x**2.0 + 2) * math.e**x)
            __function = "func_2"
        else:
            graph.eval_func = lambda x: x**4.0 - 3 * x**2.0 + 2 * x
            __function = "func_1"

    def create_graph2d_view ():
        frame = VFrame (Label ("Graph2D"))
        frame.topleft = 10, 10

        # Create the graph.
        graph = Graph2D (400, 400)

        # Lock it, because we set some necessary information and want to
        # avoid excessive update() calls.
        graph.lock ()

        # Scale units for the x and y axis.
        graph.scale_units = ("cm", "kp")

        # Point of origin.
        graph.origin = 200, 200

        # We want to see negative values.
        graph.negative = True

        # The evaluation function and data to use.
        graph.eval_func = lambda x: x**4.0 - 3 * x**2.0 + 2 * x
        if Numeric:
            graph.data = Numeric.arrayrange (-10, 10, .001).tolist()
        else:
            graph.data = numpy.arange (-10, 10, .001).tolist()
        # Done, unlock.
        graph.unlock ()

        button = Button ("Change function")
        button.connect_signal (SIG_CLICKED, change, graph)

        frame.add_child (graph, button)

        return frame

    if __name__ == "__main__":
        # Initialize the drawing window.
        re = Renderer ()
        re.create_screen (450, 500)
        re.title = "Graph2D examples"
        re.color = (234, 228, 223)
        re.add_widget (create_graph2d_view ())
        # Start the main rendering loop.
        re.start ()

Example 44. Graph2D example

### StatusBar

The `StatusBar` widget class can display various text information using a stack system as well as the current date and time. It also supports the placement of widgets on its area.

To create a new `StatusBar` widget, you simply invoke its constructor with no arguments.

    statusbar = StatusBar ()

To set set the current information to display, the `push_tip()` method has to be used.

    statusbar.push_tip ("Display this tip")

To remove the currently displayed information and to show the previous information the `pop_tip()` method has to be used.

    statusbar.pop_tip ()

The currently displayed information can be received using the current_tip attribute or the `get_current_tip()` method.

    info = statusbar.current_tip
    info = statusbar.get_current_tip()

To show or hide the information on the `StatusBar` the tips attribute and `show_tips` method are used.

    statusbar.tips = True
    statusbar.show_tips (False)

You also can show or hide the date to display using the date attribute and `show_date` method,

    statusbar.date = True
    statusbar.show_date (False)

You can supply your own date and time format string to customize the date output. The date_format attribute and `set_date_format()` method allow you to use python specific date format strings, which can be understood by python's `datetime.strftime()` method.

    statusbar.date_format = "%x"
    statusbar.set_date_format ("%H:%M")

To get the currently displayed date and time, use the current_date attribute. Its value matches the set date_format attribute.

    date = statusbar.current_date

You can customize the size occupied by the displayed information and date using the tip_width and date_width properties and `set_tip_width` and `set_date_width` methods.

    statusbar.tip_width = 50 # Set the information display width to 50 px.
    statusbar.set_tip_width (50)

    statusbar.date_width = 50 # Set the date display width tto 50 px.
    statusbar.set_date_width (50)

You can find the following example as a python script under `examples/statusbar.py`.

    # StatusBar examples.
    from ocempgui.widgets import *
    from ocempgui.widgets.Constants import *

    def _update_tip (statusbar, button):
        statusbar.pop_tip ()
        statusbar.push_tip ("Button '%s' was clicked" % button.text)

    def _create_vframe (text):
        frame = VFrame (Label (text))
        frame.spacing = 5
        frame.align = ALIGN_LEFT
        return frame

    def create_statusbar_view ():
        table = Table (1, 3)
        table.spacing = 5

        # Create and display a simple StatusBar with some children.
        frame = _create_vframe ("StatusBar")
        status = StatusBar ()
        button1 = Button ("Button")
        button1.connect_signal (SIG_CLICKED, _update_tip, status, button1)
        button2 = CheckButton ("Empty")
        button2.connect_signal (SIG_CLICKED, _update_tip, status, button2)

        status.add_child (button1, button2)

        button = Button ("Testbutton")
        button.connect_signal (SIG_CLICKED, _update_tip, status, button)
        frame.add_child (button, status)

        table.add_child (0, 0, frame)
        return table

    if __name__ == "__main__":
        # Initialize the drawing window.
        re = Renderer ()
        re.create_screen (450, 150)
        re.title = "StatusBar examples"
        re.color = (234, 228, 223)
        re.add_widget (create_statusbar_view ())
        # Start the main rendering loop.
        re.start ()

Example 45. StatusBar example

### TooltipWindow

The `TooltipWindow` is a non-interactive widget that can display a short to medium amount of text and can be used to display additional information and descriptions. It uses a certain background color to be easily distinguished from other widgets.

To create a `TooltipWindow` widget, you simply invoke its constructor with the text to display.

    window = TooltipWindow ("A message to display")

To set the text after creation, use the text attribute or `set_text()` method.

    window.text = "New Text"
    window.set_text ("New Text")

You can find the following example as a python script under `examples/tooltipwindow.py`.

    # TooltipWindow examples
    import pygame.mouse
    from ocempgui.widgets import *
    from ocempgui.widgets.Constants import *

    __tooltip = None

    def _make_tooltip (tip, renderer):
        global __tooltip

        # Destroy the tooltip, if it exists.
        if __tooltip:
            __tooltip.destroy ()

        # Create a new tooltip.
        __tooltip = TooltipWindow (tip)
        x, y = pygame.mouse.get_pos ()
        __tooltip.topleft = x + 8, y - 5
        __tooltip.depth = 99 # Make it the topmost widget.

        renderer.add_widget (__tooltip)

    def _destroy_tooltip ():
        # Destroy the tooltip, if it exists.
        global __tooltip
        if __tooltip:
            __tooltip.destroy ()
            __tooltip = None

    def create_tooltip_view (renderer):

        frame = VFrame ()
        frame.border = BORDER_NONE
        frame.spacing = 20

        button1 = Button ("Move the mouse over me")
        button1.tooltip = "An enhanced description"
        button1.connect_signal (SIG_ENTER, _make_tooltip, button1.tooltip, renderer)
        button1.connect_signal (SIG_LEAVE, _destroy_tooltip)

        button2 = Button ("And over me, too")
        button2.tooltip = "Another description"
        button2.connect_signal (SIG_ENTER, _make_tooltip, button2.tooltip, renderer)
        button2.connect_signal (SIG_LEAVE, _destroy_tooltip)

        frame.children = button1, button2

        return frame

    if __name__ == "__main__":
        # Initialize the drawing window.
        re = Renderer ()
        re.create_screen (200, 150)
        re.title = "TooltipWindow examples"
        re.color = (234, 228, 223)
        re.add_widget (create_tooltip_view (re))
        # Start the main rendering loop.
        re.start ()

Example 46. TooltipWindow example

## Widget components

The following section covers the usage of the components used by the `ocempgui.widgets` module. Components denote elements, which are strongly wired with or used by a widget, but do not inherit from the `BaseWidget` in any way. The components can be found in the `ocempgui.widgets.components` submodule.

### ListItem

The `ListItem` component is an abstract base class for creating own item implementations, which are suitable for the usage in list or tree widgets. It contains a set of attributes and methods, which make it ready to be used in the `ListItemCollection` collection class.

You usually will not create `ListItem` objects directly, but instead subclass them, whenever you need a more advanced or specialized item type, than the `TextListItem` and `FileListItem` offer.

Similar to the widgets inheriting from the `BaseWidget` class, the `ListItem` offers a style attribute, that lets you set up an instance specific look and feel for it.

    # Create the instance specific style information.
    listitem.create_style()
    listitem.style['font']['size'] = 16

The collection, the item should be or is bound to, can be read and set by accessing its collection attribute.

    if listitem.collection != my_collection:
        listitem.set_collection (my_collection)

To make the `ListItem` suitable for tree or list widgets, it contains a selected attribute that, as the name says, can be used by the according widget implementation to set or determine the selection state of the item.

    if not listitem.selected:
        listitem.selected = True

For optimization purposes in drawing the `ListItem` contains, similar to the `BaseWidget`, a dirty attribute and `set_dirty()` method.

    listitem.dirty = True

Changing its value to True will try to inform its collection about that the item has changed, so that an updating process can be started.

For concrete implementations and examples, the author recommends to look at the source code of the `TextListItem` and `FileListItem` implementations, which will be explained hereafter.

### TextListItem

The `TextListItem` - as its name suggests - is a `ListItem`, that is able to store and show text. Besides this it does not offer anything oustanding so that its only improvements are to set and get text.

A `TextListItem` is created by passing the text it should store to its constructor.

    listitem = TextListItem ("This is a TextListItem")

It is not needed to set the text explicitly at creation time. It can be fetched or changed at any time with the text attribute.

    listitem.text = "I contain changed text."

### FileListItem

The `FileListItem` is an advanced `TextListItem`, which contains additional attributes to make it suitable for storing different file related information.

The `FileListItem` requires besides a text the file mode information (those are explained in detail in the stat documentation).

    # Retrieve the stats for a file.
    st = os.stat ("myfile")

    # Create the item with the file modes.
    listitem = ("myfile", st.st_mode)

Dependant on the passed file mode, which will be stored in the filetype attribute,

    if stat.S_ISDIR (listitem.filetype):
        print "Item %s is a directory, hooray!" % listitem.text

the `FileListItem` will set load a matching icon into its icon attribute (at construction time). This icon will be taken from the `Icons16x16` icon constants of the `ocempgui.widgets.images` submodule by default.

### ListItemCollection

The `ListItemCollection` is a wrapper around the python builtin type list. It supports a set of most important list operations, such as iterators, slicing and sorting. Several methods, especially the arithmetic overloads (addition, mulitplication, etc.) are not available. For a complete list of supported operations, browse the documentation strings of the `ListItemCollection`.

The `ListItemCollection` is created by simply invoking its constructor.

    collection = ListItemCollection ()

Items can be added in a similar way to the list type using the `insert()`, `append()` or `extend()` methods for example.

    collection.append (item1)
    collection.insert (9, item2)

The specialities of the `ListItemCollection` are, that it only accepts `ListItem` objects as valid items on the one hand and supports two notification slots on the other. Those notification slots are implemented as attributes, item_changed and list_changed. Any method or function can be bound to those to get informed about item changes in the list (e.g. an item has changed its contents) and list changes in general (items were added, removed, etc.). The item_changed attribute additionally passes the affected item to the notification handler, while list_changed() will pass the `ListItemCollection`.

You can find the following example as a python script under `examples/listitemcollection.py`.

    # ListItemCollection example.
    from ocempgui.widgets.components import ListItemCollection, TextListItem

    # Item change handler.
    def item_has_changed (item):
        print "Item '%s' has changed" % item.text

    # List change handler.
    def list_has_changed (l):
        print "List now contains %d item(s)" % l.length

    collection = ListItemCollection ()

    # Set up a notification handler for item changes.
    collection.item_changed = item_has_changed

    # Set up a notification handler for list changes
    collection.list_changed = list_has_changed

    for i in xrange (5):
        collection.append (TextListItem ("Item no. %d" % i))

    collection[2].text = "New text in item 3"

    # Use a tuple as constructor argument.
    items = (TextListItem ("String 1"), TextListItem ("String 2"),
             TextListItem ("String 3"))
    collection = ListItemCollection (items)
    print "New collection:"
    print collection

Example 47. ListItemCollection example

## Creating custom widgets

Sometimes it is necessary to create an own, specialized widget type, that matches your exact needs. The following section will give you an rough overview about what you have to keep in mind and about what you have to take care, when creating custom widgets. You are encouraged to browse the existing widget sourcecode in order to see, how the one or other is implemented.

In this section, you will create an own widget, that lets the user play the famous game Tic Tac Toe and is able to deal with a custom SIG_TICTACTOE event.

### Designing the basis

First of all you should make yourself a picture about how the widget should look like and what it should be able to do. In our case, this would be an area consisting of 3x3 squares, of which each is clickable exactly one time and should fill - dependant on whose turn it is - the square with either a cross or a circle. When the game is ended, the widget should note that by sending a corresponding event, so that other widgets can update themselves according to that.

After you know about how it should look like and what it should be able to do, its time to collect the things you need. Whenever it is possible, you should use existing code or classes, so that you do not need to reinvent anything.

Luckily our example can be completed by using a `Table` widget with 3 rows and 3 columns and nine `ImageButton` widgets, that can display the circle or cross. The only things, that do not exist are the signal and graphics for a circle and cross.

### Implementing the widget basics

We start by creating a custom class, that inherits directly from the `Table`.

    from ocempgui.draw import Image
    from ocempgui.widgets import Table
    from ocempgui.widgets.Constants import *

    class TicTacToe (Table):
        """The famous game as widget.
        """
        def __init__ (self):
            Table.__init__ (self, 3, 3)

Now we have to place nine blank `ImageButton` widgets into the table. We will size them to 60x60 px, so that they will not resize later, when we set their images, which have a size of 48x48 px.

    class TicTacToe (Table):
        ...
        def __init__ (self):
            Table.__init__ (self, 3, 3)
            for i in xrange (3):
                for j in xrange (3):
                    button = ImageButton ("")
                    button.minsize = 60, 60
                    self.add_child (i, j, button)

That was not too complicated, but the buttons also need to react upon clicks and they have to distinct between two players.

    class TicTacToe (Table):
        ...
        def __init__ (self):
            Table.__init__ (self, 3, 3)
            self._curplayer = "Player 1"

            for i in xrange (3):
                for j in xrange (3):
                    button = ImageButton ("")
                    button.minsize = 60, 60
                    self.add_child (i, j, button)
                    button.connect_signal (SIG_CLICKED, self._clicked, button,
                                           i, j)

This will cause them to raise the `_clicked()` method, which we now implement:

    class TicTacToe (Table):
        ...
        def __init__ (self):
            ...

        def _clicked (self, button, i, j):
            """Sets the image of the button, if not already done.
            """
            button = self.grid[(i, j)]
            # Check, if it is not already set.
            if button.picture == None:
                if self._curplayer == "Player 1":
                    # Use the cross.
                    button.picture = "cross.png"
                    self._curplayer = "Player 2"
                else:
                    button.picture = "circle.png"
                    self._curplayer = "Player 1"

The widget is fairly usable now, but still lacks the event mechanism, which will be explained in the next section.

### Implementing the event handlers

To allow a better interactivity with the TicTacToe widget, it will invoke its event handlers, whenever a player clicked on a square. Dependant on what happens, the event mechanism should indicate this. Thus it will have to pass additional data to the event handlers. We want it to send the following data:

- TICTACTOE_VALIDSQUARE, if the player clicked on an unoccupied button,

- TICTACTOE_INVALIDSQUARE, if the player clicked on an occupied button,

- TICTACTOE_WIN, if the one of the players wins. Further input should not be allowed afterwards.

Implementing the first and second event is easy and we only have to add four lines of code to our existing class. The first line will define the SIG_TICTACTOE signal, the next three lines our signal data we want to send.

    from ocempgui.widgets import Table
    from ocempgui.widgets.Constants import *

    SIG_TICTACTOE = "tictactoe"
    TICTACTOE_WIN = 1
    TICTACTOE_VALIDSQUARE = 0
    TICTACTOE_INVALIDSQUARE = -1

    class TicTacToe (Table):
        """The famous game as widget.
        """
        ...

The second line prepares the TicTacToe widget to connect callbacks to the SIG_TICTACTOE signal.

    class TicTacToe (Table):
        """The famous game as widget.
        """
        def __init__ (self):
            ...
            self._signals[SIG_TICTACTOE] = []

The next two line will cause the widget to run the appropriate signal handlers upon clicks on the buttons.

    class TicTacToe (Table):
        ...
        def _clicked (self, button, i, j):
            """Sets the image of the button, if not already done.
            """
            button = self.grid[(i, j)]
            # Check, if it is not already set.
            if button.picture == None:
                if self._curplayer == "Player 1":
                    button.picture = "cross.png"
                    self._curplayer = "Player 2"
                else:
                    button.picture = "circle.png"
                    self._curplayer = "Player 1"
                self.run_signal_handlers (SIG_TICTACTOE, TICTACTOE_VALIDSQUARE)

            else:
                self.run_signal_handlers (SIG_TICTACTOE, TICTACTOE_INVALIDSQUARE)

The third event handler requires a bit more work as we have to check, if there are three buttons displaying the same picture in a row. The most simple (and unoptimized) algorithm for that would be:

- Check all columns for the first, second and third line.

- Check all lines for the first, second and third column.

- Check diagonal the squares located at (0, 0), (1, 1) and (2, 2).

- Check diagonal the squares located at (0, 2), (1, 1) and (2, 0).

    class TicTacToe (Table):
        ...
        def _check_input (self):
            """Checks for three in a row.
            """
            three = False
            image = None

            # Check the columns
            for i in xrange (3):
                if three:
                    break
                image = self.grid[(i, 0)].path
                if image:
                    three = (self.grid[(i, 1)].path == image) and \
                            (self.grid[(i, 2)].path == image)

            if not three:
                # Check the rows.
                for i in xrange (3):
                    if three:
                        break
                    image = self.grid[(0, i)].path
                    if image:
                        three = (self.grid[(1, i)].path == image) and \
                                (self.grid[(2, i)].path == image)

            if not three:
                # Diagonal left to right
                image = self.grid[(0, 0)].path
                if image:
                    three = (self.grid[(1, 1)].path == image) and \
                            (self.grid[(2, 2)].path == image)
                if not three:
                    # Diagonal right to left
                    image = self.grid[(2, 0)].path
                    if image:
                        three = (self.grid[(1, 1)].path == image) and \
                                (self.grid[(0, 2)].path == image)

            if three:
                self._finished = True
                self.run_signal_handlers (SIG_TICTACTOE, TICTACTOE_WIN)

The check has to be performed right after a valid input. The _finished attribute will be used to check, if input is still possible or not. We have to place it in the constructor code

    class TicTacToe (Table):
        """The famous game as widget.
        """
        def __init__ (self):
            ...
            self._finished = False

as well as to check its value in the button callback, in which we have to add the input check, too.

        def _clicked (self, button, i, j):
            """Sets the image of the button, if not already done.
            """
            if self._finished:
                return

            button = self.grid[(i, j)]
            # Check, if it is not already set.
            if button.picture == None:
                if self._curplayer == "Player 1":
                    # Use the cross.
                    button.picture = "cross.png"
                else:
                    button.picture = "circle.png"
                self.run_signal_handlers (SIG_TICTACTOE, TICTACTOE_VALIDSQUARE)
                self._check_input ()

                # Set it after the check, so we can get the correct player name.
                if self._curplayer == "Player 1":
                    self._curplayer = "Player 2"
                else:
                    self._curplayer = "Player 1"
            else:
                self.run_signal_handlers (SIG_TICTACTOE, TICTACTOE_INVALIDSQUARE)

As you see, switching the current player is done right after running signal handler and input check now, so that clicks onto an already occupied buttons do not cause a player change.

So far we are done. You can play a basic Tic Tac Toe game with your newly created widget and the widget can react upon the user input. It is however neither very usable nor nice to look at. All those things will be explained in the next section, but first let us look at the complete code.

Note that an additional curplayer attribute is at the bottom of the code, so that it is possible to find out, who's turn it is.

You can find the code as a python script under `examples/tictactoe/TicTacToeSimple.py`. There is also a small starting test script called `tictactosimple.py` as well as the both needed graphics.

    from ocempgui.widgets import *
    from ocempgui.widgets.Constants import *

    SIG_TICTACTOE = "tictactoe"
    TICTACTOE_WIN = 1
    TICTACTOE_VALIDSQUARE = 0
    TICTACTOE_INVALIDSQUARE = -1

    class TicTacToe (Table):
        """The famous game as widget.
        """
        def __init__ (self):
            Table.__init__ (self, 3, 3)
            self._curplayer = "Player 1"
            self._finished = False

            for i in xrange (3):
                for j in xrange (3):
                    button = ImageButton ("")
                    button.minsize = 60, 60
                    self.add_child (i, j, button)
                    button.connect_signal (SIG_CLICKED, self._clicked, button,
                                           i, j)
            self._signals[SIG_TICTACTOE] = []

        def _clicked (self, button, i, j):
            """Sets the image of the button, if not already done.
            """
            if self._finished:
                return

            button = self.grid[(i, j)]
            # Check, if it is not already set.
            if button.picture == None:
                if self._curplayer == "Player 1":
                    # Use the cross.
                    button.picture = "cross.png"
                else:
                    button.picture = "circle.png"
                self.run_signal_handlers (SIG_TICTACTOE, TICTACTOE_VALIDSQUARE)
                self._check_input ()

                # Set it after the check, so we can get the correct player name.
                if self._curplayer == "Player 1":
                    self._curplayer = "Player 2"
                else:
                    self._curplayer = "Player 1"
            else:
                self.run_signal_handlers (SIG_TICTACTOE, TICTACTOE_INVALIDSQUARE)

        def _check_input (self):
            """Checks for three in a row.
            """
            three = False
            image = None

            # Check the columns
            for i in xrange (3):
                if three:
                    break
                image = self.grid[(i, 0)].path
                if image:
                    three = (self.grid[(i, 1)].path == image) and \
                            (self.grid[(i, 2)].path == image)

            if not three:
                # Check the rows.
                for i in xrange (3):
                    if three:
                        break
                    image = self.grid[(0, i)].path
                    if image:
                        three = (self.grid[(1, i)].path == image) and \
                                (self.grid[(2, i)].path == image)

            if not three:
                # Diagonal left to right
                image = self.grid[(0, 0)].path
                if image:
                    three = (self.grid[(1, 1)].path == image) and \
                            (self.grid[(2, 2)].path == image)
                if not three:
                    # Diagonal right to left
                    image = self.grid[(2, 0)].path
                    if image:
                        three = (self.grid[(1, 1)].path == image) and \
                                (self.grid[(0, 2)].path == image)

            if three:
                self._finished = True
                self.run_signal_handlers (SIG_TICTACTOE, TICTACTOE_WIN)

        curplayer = property (lambda self: self._curplayer)

Example 48. Simple TicTacToe widget

## Advanced custom widgets

TODO

## Changing the widget appearance

The `ocepgui.widgets` module offers two possibilities to change the provided widget appearance. This section covers the necessary tasks, which have to be performed to change create an own look and feel to match your personal needs.

The first part will give you a rough overview about how the styling and drawing system of the `ocempgui.widgets` module words, while the second will explain the style files and syntax, that deal with basic attributes such as background colors or fonts. The last part then gives an in-depth explanation, how to provide own drawing methods for a widget to spend it a completely different look and feel (such as rounded borders for buttons for example).

### How widgets are drawn

The rendering engine contains several methods to draw each widget and some generalized methods for some commonly used parts such as the basic widget surface. The widget to draw is passed to its matching drawing method, which will look up its style settings and then draw it.

Figure 3. Widget drawing process

The `Style` supports cascading the widget style settings. This means, that it will, when it retrieves the widget style and does not find the style setting it needs, walk through the inherited classes (the __mro__ attribute) of the widget until it finds the setting. The last instance it looks the setting up in is the "default" entry of its styles attribute.

### Customizing the theme files

Theme files for OcempGUI define the most basic settings for the widgets, such as the background color or the font to use. They however do not cause the widget to look completely different. The basic widget layout will stay the same.

The theme files are read by the currently active `Style` class (which is set in `base.GlobalStyle`) and their information will be stored in its styles dictionary.

The currently active theme information for a specific widget class are stored in the styles attribute by using its lowercase classname. This means that the specific theme for a `Button` widget is stored in `Style.styles["button"]`. For a `Label` widget it would be `Style.styles["label"]` and so on.

Such a theme entry is a dictionary, that contains various information about the background and foreground color for the different supported widget states, the font settings for that widget and more. The complete list of possible settings can be found in the documentation of the `Style`, so it will not be covered in detail here.

Setting up individual styles should be done using an own file for them, so you can easily change them without touching your program code. Let us create a separate theme file, that will cause the buttons to use a blue background color and the labels a different font and foreground color.

After creating the file for that (the author recommends using the suffix ".rc" for theme files), we use the python syntax for the contents. First we have to let the file and its content know about the supported widget states, thus we will import the `Constants` of the `ocempgui.widgets` module.

    from ocempgui.widgets import Constants

### Note

Do not use any `from ... import *` within the theme files to avoid a bloated `Style` class. The theme loader give you much freedom including the possibility to make many mistakes. You also should not import anything except the `Constants` module into the theme file, too.

Now we will set up our theme dictionary for the `Button` widget.

    from ocempgui.widgets import Constants

    button = { "bgcolor" : { Constants.STATE_NORMAL : (18, 12, 135),
                             Constants.STATE_ENTERED : (32, 25, 164),
                             Constants.STATE_ACTIVE : (18, 12, 135),
                             Constants.STATE_INSENSITIVE : (54, 51, 106) }
               }

The above code will set, after loading the style file, the background color of any `Button` to different types of a dark blue color. It also will affect any inherited widget, that does not

- implement and own style explicitly,

- define the style setting in its own style.

You can easily see this by placing a `Button` and a `CheckButton` side by side.

Let us now set the styles for the `Label` widget. The first part sets up the font, its size and if antialiasing should be used, the second one sets up different colors to use for the text according to the widget its state.

    from ocempgui.widgets import Constants

    ...
    label = { "font" : { "name" : "Helvetica", "size" : 16, "alias" : True },
              "fgcolor" : { Constants.STATE_NORMAL : (250, 250, 250),
                            Constants.STATE_ENTERED : (150, 150, 150),
                            Constants.STATE_ACTIVE : (0, 0, 0),
                            Constants.STATE_INSENSITIVE : (235, 235, 235) }
              }

Typing in those `Constants...` entries can become a lot of work, especially with complex themes. Thus OcempGUI allows you to define variables to ease your life. Any entry, that is prefixed with an underscore, "_", will be handled as variable, ignored by the loading mechanisms and thus does not go into the style dictionary.

With this in mind, let's substitute those lengthy constants with some variables.

    from ocempgui.widgets import Constants

    # Variables, that will be used to ease the life.
    _normal = Constants.STATE_NORMAL
    _entered = Constants.STATE_ENTERED
    _active = Constants.STATE_ACTIVE
    _insensitive = Constants.STATE_INSENSITIVE

    button = { "bgcolor" : { _normal : (18, 12, 135),
                             _entered : (32, 25, 164),
                             _active : (18, 12, 135),
                             _insensitive : (54, 51, 106) }
               }
    ...

Of course you can also use more than a single underscore. The only importance is, that the first letter of the entry starts with an underscore. Thus valid variables would be

    _red = (255, 0, 0)
    __myfont = "path/to/font.ttf"
    ____________a_pretty_long_variable_that_is_completely_useless = None

As you see, setting up own themes for widgets is not a complex task. Let us now examine the complete code and a small example, that will make use of the just created theme.

You can find the code and theme as python scripts under `examples/theme_example.rc` and `examples/theme.py`.

    from ocempgui.widgets import Constants

    # Variables, that will be used to ease the life.
    _normal = Constants.STATE_NORMAL
    _entered = Constants.STATE_ENTERED
    _active = Constants.STATE_ACTIVE
    _insensitive = Constants.STATE_INSENSITIVE

    button = { "bgcolor" : { _normal : (18, 12, 135),
                             _entered : (32, 25, 164),
                             _active : (18, 12, 135),
                             _insensitive : (54, 51, 106) }
               }
    label = { "font" : { "name" : "Helvetica", "size" : 16, "alias" : True },
              "fgcolor" : { _normal : (250, 250, 250),
                            _entered : (150, 150, 150),
                            _active : (0, 0, 0),
                            _insensitive : (235, 235, 235) }
              }

    # Theme usage example.
    from ocempgui.widgets import base, Renderer, Button, Label

    # Load the theme.
    base.GlobalStyle.load ("theme_example.rc")

    # Create screen.
    re = Renderer ()
    re.create_screen (200, 100)
    re.title = "Theme example"
    re.color = (250, 250, 250)

    # Create widgets.
    button = Button ("Button")
    button.topleft = 5, 5
    label = Label ("Label")
    label.topleft = 100, 5

    re.add_widget (button, label)
    re.start ()

Example 49. Customizing the themes

### Using own drawing routines

Whenever you need an completely different layout, the creation of own theme files will not be enough. This section explains how to modify and/or override the drawing methods for the widgets.

First you should make yourself clear about if you need to provide an own layout only for specific instances of a widget or if those widgets always should be drawn that way. Dependant on your needs, you have several possibilites.

- Subclass the widget and override its `draw()` and `draw_bg()` methods.

- Bind the `draw()` and `draw_bg()` methods of the instance to your own methods or functions at runtime.

- Provide an own drawing method for the widget type and bind it to the set drawing engine.

- Implement an own drawing engine and bind it to the `Style` instance.

The first both entries should be self-explanatory. The only thing you have to keep in mind when overriding the widget's drawing methods are, that you must invoke at least the `BaseWidget.draw()` method. This method updates the internals of the widget after drawing the background, does surface conversions and more, so it is an absolutely necessary method to be invoked.

Of course you can also invoke the parent's `draw()` method, if you (just) want to add something to the widget's look instead of implementing all drawing yourself.

    class OwnButton (Button):
        ...
        def draw_bg (self):
            ... # Own background drawing implementation.

        def draw (self):
            # We want the drawing routines of the Button to be executed and
            # just add something to them.
            Button.draw (self)
            ...

    class OwnButton2 (Button):
        ...
        def draw_bg (self):
            ... # Own drawing implementation.

        def draw (self):
            # Do not process any drawing of the Button, but use the BaseWidget
            # directly to update the widget internals, because we do anything
            # ourselves
            BaseWidget.draw (self)
            ...

So far for the first both entries of the above list. Now let's look at manipulating the drawing engine by overriding it (binding a new method should not be any problem for you, not?).

We will create an own drawing engine subclass using the provided `DefaultEngine` and use an own drawing method for `Label` widgets, which adds a dropshadow to them by default. After creating this subclass we will use an instance of it for our own small test application.

The first we have to do is to inherit from the `DefaultEngine` subclass. The class is not located in the module directly, but installed as additional data and can be imported with help of the DEFAULTDATADIR constant.

    # Drawing engine usage example.
    from ocempgui.widgets import *
    from ocempgui.widgets.Constants import DEFAULTDATADIR

    # Get the path where the theme engines are usually installed.
    import sys
    sys.path.append (DEFAULTDATADIR)
    from themes import default

    # Override the DefaultEngine with its drawing definitions so that we can
    # implement our own draw_label() method.
    class DropShadowEngine (default.DefaultEngine):
        def __init__ (self, style):
            default.DefaultEngine.__init__ (self, style)

Now our own drawing engine contains anything, the `DefaultEngine` class contains. To provide our own drawing method for the `Label`, we have to override the matching method, which is `draw_label()`.

As you can see from its signature, it receives one argument, the `Label` object, for which the surface should be created.

### Note

All widget drawing methods follow the same naming scheme, which is draw_WIDGETTYPE (self, widget) with widgettype being the all-lowercase classname.

        def draw_label (self, label):
            """Overrides the label drawing method and adds a dropshadow."""
            # We do not care about multiline labels. Thus pass those to the
            # parent.
            if label.multiline:
                return DefaultEngine.draw_label (self, label)

To keep it simple, we do not take care of multiline labels for now, thus we let its parent handle those.

Now we shorten some attributes, which we will need in our method more often.

        def draw_label (self, label):
            ...
            cls = label.__class__
            state = label.state

            # Peek the style of the label so we can get the colors later.
            st = label.style or self.create_style (cls)

The __class__ and state attributes are used by many methods of the `DefaultEngine` class to look up the theme information of the widget. The `st` variable will be used to get and set the matching color for the dropshadow of our `Label`.

Now we have to get the foreground color to use for the text and store it temporarily as we will modify it in the `st` variable later.

        def draw_label (self, label):
            ...
            # Save the label color temporarily as we will change it for the
            # dropshadow. Because we are using references, not plain style
            # copies, we have to do this.
            fgcolor = self.get_style_entry (cls, st, "fgcolor", state)

            # The 2px added here are used for the dropshadow.
            width = 2 * label.padding + 2
            height = 2 * label.padding + 2

We also set up the width and height, our `Label` surface will occupy. Because the `Label` offers a padding attribute, we have to take it into account for the surface size.

The basics are set up, so that we can proceed with drawing the surfaces for our widget.

        def draw_label (self, label):
            ...
            if label.mnemonic[0] != -1:
                front = self.draw_string_with_mnemonic \
                        (label.text, state, label.mnemonic[0], cls, st)
                # Swap colors.
                st["fgcolor"] = { state : (100, 100, 100) }
                drop = self.draw_string_with_mnemonic \
                       (label.text, state, label.mnemonic[0], cls, st)
            else:
                front = self.draw_string (label.text, state, cls, st)
                # Swap colors.
                st["fgcolor"] = { state : (100, 100, 100) }
                drop = self.draw_string (label.text, state, cls, st)

As you can see, we first look, if a mnemonic is set for the `Label` and then use either the mnemonic string drawing method or the simple string drawing method. We do that twice, for the normal text and its dropshadow. In line eleven and nineteen we swap the foreground color of the `st` variable with a bright grey one.

So we have our both surfaces now and are nearly done. But we have to respect some definitions of the `BaseWidget` and we have to reset the swapped colors.

        def draw_label (self, label):
            ...
            # Surface creation done. Restore the colors.
            st["fgcolor"][state] = fgcolor

            # Get the size of the surface(s) and add it to the complete
            # width and height, the label will occupy.
            rect = front.get_rect ()
            width += rect.width
            height += rect.height

            # Guarantee size.
            width, height = label.check_sizes (width, height)

Now we are ready to blit the surfaces and return the complete label surface.

        def draw_label (self, label):
            ...
            # Blit all and return the label surface to the caller.
            surface = self.draw_rect (width, height, label.state, cls, st)
            surface.blit (drop, (label.padding + 2, label.padding + 2))
            surface.blit (front, (label.padding, label.padding))
            return surface

So far so good. We now have our own drawing engine, that will draw `Label` widgets with a dropshadow by default. The very last thing to do is to make the `omcepgui.widgets` module use our own class instead of the default. This is done by assigning the base.GlobalStyle.engine attributes an instance of our own class in the code. The drawing methods will then make use of it.

    # Set out own drawing engine in the Style class.
    base.GlobalStyle.engine = DropShadowEngine (base.GlobalStyle)

Now all `Label` widgets will use the just created `draw_label()` method.

The complete code of the previous example follows. It includes some test code, so you can easily evaluate the results.

You can find the code as python script under `examples/drawing_engine.py`.

    # Drawing engine usage example.
    from ocempgui.widgets import *
    from ocempgui.widgets.Constants import DEFAULTDATADIR

    # Get the path where the theme engines are usually installed.
    import sys
    sys.path.append (DEFAULTDATADIR)
    from themes import default

    # Override the DefaultEngine with its drawing definitions so that we can
    # implement our own draw_label() method.
    class DropShadowEngine (default.DefaultEngine):

        def __init__ (self, style):
            default.DefaultEngine.__init__ (self, style)

        def draw_label (self, label):
            """Overrides the label drawing method and adds a dropshadow."""
            # We do not care about multiline labels. Thus pass those to the
            # parent.
            if label.multiline:
                return DefaultEngine.draw_label (self, label)

            cls = label.__class__
            state = label.state

            # Peek the style of the label so we can get the colors later.
            st = label.style or self.style.get_style (cls)

            # Save the label colour temporarily as we will change it for the
            # dropshadow. Because we are using references, not plain style
            # copies, we have to do this.
            fgcolor = self.style.get_style_entry (cls, st, "fgcolor", state)

            # The 2px added here are used for the dropshadow.
            width = 2 * label.padding + 2
            height = 2 * label.padding + 2

            # Backup the color.
            tmp = None
            if st.has_key ("fgcolor"): # Is fgcolor defined?
                tmp = st["fgcolor"]

            # Draw the text.
            front = None
            drop = None
            if label.mnemonic[0] != -1:
                front = self.draw_string_with_mnemonic \
                        (label.text, state, label.mnemonic[0], cls, st)
                # Swap colors.
                st["fgcolor"] = WidgetStyle ({ state : (100, 100, 100) })
                drop = self.draw_string_with_mnemonic \
                       (label.text, state, label.mnemonic[0], cls, st)
            else:
                front = self.draw_string (label.text, state, cls, st)
                # Swap colors.
                st["fgcolor"] = WidgetStyle ({ state : (100, 100, 100) })
                drop = self.draw_string (label.text, state, cls, st)

            # Surface creation done. Restore the colors.
            if not tmp:
                del st["fgcolor"]
            else:
                st["fgcolor"] = tmp

            # Get the size of the surface(s) and add it to the complete
            # width and height, the label will occupy.
            rect = front.get_rect ()
            width += rect.width
            height += rect.height

            # Guarantee size.
            width, height = label.check_sizes (width, height)

            # Blit all and return the label surface to the caller.
            surface = self.draw_rect (width, height, label.state, cls, st)
            surface.blit (drop, (label.padding + 2, label.padding + 2))
            surface.blit (front, (label.padding, label.padding))
            return surface

    if __name__ == "__main__":
        re = Renderer ()
        re.create_screen (200, 200)
        re.title = "Style example."
        re.color = (234, 228, 223)

        # Set out own drawing engine in the Style class.
        base.GlobalStyle.engine = DropShadowEngine (base.GlobalStyle)

        label = Label ("Example label")
        label.create_style ()["font"]["size"] = 30
        label.topleft = 10, 10

        label2 = Label ("#Mnemonic")
        label2.create_style ()["font"]["size"] = 30
        label2.topleft = 10, 60

        button = CheckButton ("Dropshadow")
        button.topleft = 10, 100
        re.add_widget (label, label2, button)
        re.start ()

Example 50. Customizing the widget drawing routines

### Changing the appearance of single instances

While the last sections dealt with changing the appearance of whole widget classes, this section will explain how to change particular bits of a single widget instance.

## The layer and indexing system

### Layers

The `Renderer` class supports z-axis layering by drawing and keeping widgets on top of others as shown in the figure beneath. Layers are set up automatically, whenever a widget with a certain depth does not match the existing layers. Thus you usually will not have to deal with the layer internals of the `Renderer` class, but instead adjust the layers using the different widgets. Sometimes it might be necessary to manually adjust portions of the layer behaviour, especially if layers should be activated automatically on certain actions.

Figure 4. Layer view on the display.

The currently active layer, which has the input focus, can be get and set using the active_layer attribute or `set_active_layer()` method.

    layer = renderer.active_layer
    renderer.set_active_layer (2)

active_layer will return a tuple consisting of three objects:

- an list containing the indices of the attached widgets for keyboard navigation,

- a list containing the widgets attached to the layer,

- an `EventManager` subclass, which deals with the events sent to the layer.

You should not modify the contents nor the objects directly but instead use the respective `Renderer` methods instead.

The `set_active_layer()` methods accepts both, a tuple as returned by active_layer as well as an integer, which denotes the layer to activate (similarily to the depth attribute of the `BaseWidget` class).

Both, the method and attribute, allow you to manipulate the active layer directly, so that you can enforce the focus on a certain dialog window for example.

It is also possible to cycle through the layers programmatically,using the `switch_layer()` method. The figure beaneath shows, what happens on each invocation.

    renderer.switch_layer () # Step 1
    renderer.switch_layer () # Step 2
    renderer.switch_layer () # Step 3

Figure 5. Layer cycling

### Index system

To enhance the accessibility of widgets on the screen, the `Renderer` implements the `IIndexable` interface class to let the user navigate through widgets using the keyboard. Each installed layer manages its own indexing list, so that the navigation by default always happens on the currently active layer.

The `Renderer` determines the order, widgets are navigated through, using their index attribute. The invocation of `switch_index()` will set the keyboard focus to the widget with the next higher index value. If the last widget is reached, the first widget will receive the focus again as shown in the figure below.

Figure 6. Index switching

## A. Widget hierarchy

Below you will find the Widget hierarchy of the `ocempgui.widget` module.

    BaseObject
      +-ActionListener
      `-BaseWidget
          +-Label
          +-ImageLabel
          +-Bin
          |  +-Alignment
          |  +-ButtonBase
          |  |  +-Button
          |  |  +-ImageButton
          |  |  +-ToggleButton
          |  |     +-CheckButton
          |  |     `-RadioButton
          |  |
          |  +-ScrolledWindow
          |  |  `-ScrolledList
          |  |     `-FileList
          |  |
          |  +-ViewPort
          |  |  `-ListViewPort
          |  |
          |  `-Window
          |     `-DialogWindow
          |        `-GenericDialog
          |           `-FileDialog
          +-Container
          |  +-Box
          |  +-Frame
          |  |  +-HFrame
          |  |  `-VFrame
          |  `-Table
          |
          +-Diagram
          |  `-Graph2D
          |
          +-Editable
          |  `-Entry
          |
          +-Range
          |  +-Scale
          |  |  +-HScale
          |  |  `-VScale
          |  |
          |  `-ScrollBar
          |     +-HscrolBar
          |     `-VScrollBar
          |
          +-ImageMap
          +-ProgressBar
          +-StatusBar
          `-TooltipWindow

## B. Changes between 0.1.x and 0.2.x

The following section will describe the most notably changes between the version series 0.1.x and 0.2.x, which might break the compatibility of applications. If you plan to migrate your OcempGUI application to 0.2.x, read this section carefully.

## Changes in ocempgui.access

The `AccessibleContext` class was completely removed. Because it had no practical use, this should not affect anyone.

The `Accessible` class was renamed to `IAccessible`. Make sure, that you replace any occurance of it with the new name.

The `Indexable` class was renamed to `IIndexable`. Make sure, that you replace any occurance of it with the new name.

## Changes in ocempgui.events

The `EventManager` class expects `INotifyable` objects for addition to its queues. Although it does not force objects to inherit from `INotifyable`, it will print out a warning, if an object to add does not inherit from this class. Newly created classes thus should inherit from INotifyable, if they do not already inherit from it (by e.g. inheriting from `BaseObject`).

The eventgrabber attribute of the `EventManager` was renamed to `event_grabber`. Make sure, that you replace all occurances of it accordingly, because there is no compatibility support.

The `EventManager` is a full class by now and does not implement __slots__ anymore. If your classes inherit from it, make sure, that they deal with that change correctly.

## Changes in ocempgui.widgets

Widgets are not placed using absolute coordinates anymore. Instead they are placed relative to their parent coordinates, which applies especially to boxed widgets being put in `Bins` or `Containers`. Their position attributes such as top, topleft, rect, ... thus refer to their relative position. To retrieve the absolute coordinates, you should use their `rect_to_client()` method.

The position attribute and `set_position` method of widgets are deprecated and will be removed completely in a later version. The new topleft attribute will replace them. Make sure to change your code accordingly over time.

The size attribute of widgets is no longer writeable and its function was replaced by the new minsize attribute. The `set_size()` method however is still available but deprecated. Make sure, that your code respects that change.

The eventarea attribute and `set_event_area()` method of widgets are deprecated, do not have any functionality anymore and will be removed completely in a later version. The new method `rect_to_client()` provides a read-only replacement for them in a slightly different intention.

The drawing code and behaviour heavily changed in 0.2.x, so that the widget method `draw_bg()` now will take care of drawing a widget background (usually invoking `Style.engine.draw_WIDGET()`), while `draw()` will do the rest. This should only affect user-defined widgets or inheritors, which override the default drawing code. For more details see the section called “Changing the widget appearance”.

Most `Button` widget implementations now inherit from the newly added `ButtonBase` class. This should not harm the most code, but inheritance checks might have to change accordingly. Make sure to recheck your code.

The `ScrolledWindow` class now encapsulates widgets using the `ViewPort` class. Code that relies upon the child attribute of it, should be changed accordingly.

The `get_visible_area()` method of the `ScrolledWindow` class is no longer publicly available.

The `get_scrollable_area()` if the `ScrolledWindow` class was removed without a replacement.

The `get_coords_from_value()` and `get_value_from_coords()` methods of the `Scale` and `ScrollBar` classes are no longer publicly available.

The `get_slider_size()` and `get_button_coords()` methods of the `ScrollBar` classes are no longer publicly available.

The `RenderLayer` class was removed without a replacement.

The `Renderer` class does not directly inherit from the `EventManager` and `RenderLayer` classes anymore. A replacement for the `EventManager` functionality is the new managers attribute. Code, that added user-defined objects to the `Renderer` should use the attribute and its layered behaviour from now on.

The `force_update()` method of the `Renderer` class was removed. User code should use the `update()` and/or `refresh()` methods now.

The colour for flat borders (BORDER_FLAT) is no longer retrieved using the 'fgcolor' entry, but instead uses the new 'bordercolor' style entry. Code, that made use of this should be changed to use 'bordercolor' from now on.

The `Style` no longer directly defines drawing routines. Instead it uses the drawing engine bound to its engine attribute. User code, that made use of this, has to be changed accordingly. See the section called “Changing the widget appearance” for more details.

## Example Index

### C

Creating custom widgets: Simple Tic Tac Toe widget, Implementing the event handlers
Customizing the widget drawing routines, Using own drawing routines
Customizing theme files, Customizing the theme files

### D

Draw.draw_line (), Geometric objects
Draw.draw_rect (), Geometric objects
Draw.draw_triangle (), Geometric objects

### E

Event capable objects: Adding a signal to the object , Creating event capable objects
Event capable objects: Connecting and disconnecting callbacks , Creating event capable objects
Event capable objects: Connecting the object to an event manager. , Creating event capable objects
Event capable objects: Inheriting from the BaseObject class , Creating event capable objects
Event capable objects: Ping-Pong with a BaseObject, Creating event capable objects
Event capable objects: Ping-Pong with the ActionListener , Events on demand: the ActionListener
Event capable objects: Setting up the notify() method , Creating event capable objects
Event management: Adding and removing an object to the EventManager , Setting up the event management
Event management: Enabling an object to receive events , Enabling objects to receive events
Event management: Sending events through the EventManager , Sending events
Event management: The complete event management example , Complete event management example

### F

FaderSurface example, Complex objects

### G

GUI applications: Hello World with callbacks, Events and Signals
GUI applications: Hello World with OcempGUI, Hello World with OcempGUI
GUI applications: Setting up the Renderer, Getting started
GUI components: ListItemCollection example, ListItemCollection
GUI widgets: Bin example, Bin
GUI widgets: Bin.padding example, Bin
GUI widgets: Box example, Box
GUI widgets: Button example, Button
GUI widgets: CheckButton example, CheckButton
GUI widgets: Entry example, Entry
GUI widgets: FileDialog example, FileDialog
GUI widgets: Frame example, Frames
GUI widgets: GenericDialog example, GenericDialog
GUI widgets: Graph2D example, Graph2D
GUI widgets: ImageButton example, ImageButton
GUI widgets: ImageLabel example, ImageLabel
GUI widgets: ImageMap example, ImageMap
GUI widgets: Label example, Label
GUI widgets: ProgressBar example, ProgressBar
GUI widgets: RadioButton example, RadioButton
GUI widgets: StatusBar example, StatusBar
GUI widgets: Table example, Table
GUI widgets: ToggleButton example, ToggleButton
GUI widgets: TooltipWindo example, TooltipWindow
GUI widgets: Window example, Window

### I

Image.load_image (), Image manipulation

### O

Observer Pattern: Observer example, Tracking object states - the observer pattern
ocempgui.access.papi test example, Making python objects accessible

### S

String.create_font (), Text rendering
String.create_system_font (), Text rendering
String.draw_string (), Text rendering
String.draw_string_with_bg (), Text rendering

## Glossary

API

  Application programming interface

ATK

  A library, which provides layers to accessibility solutions such as alternate input devices or online keyboards.

CVS

  See Concurrent versions system .

Concurrent versions system

  A revision control system.

GUI

  Graphical user interface.

Pygame

  A set of python modules for writing games, based on the SDL.

Papi

  Python accessibility programming interface - a wrapper around the ATK toolkit of the GNOME accessibility project, shipped with OcempGUI.

Python

  A cross-platform scripting language.

SDL

  See Simple DirectMedia Layer .

Simple DirectMedia Layer

  A cross-platform multimedia library.

Widget

  A user interface element on a screen, with which the user can interact in a passive or active way.